<commit_before>use std::{collections::HashMap, fmt, mem::transmute};

use serde::de::{self, Deserializer, Visitor};
use serde::ser::Serializer;

use crate::internal::prelude::*;
use crate::model::prelude::*;

/// Determines the action that was done on a target.
#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
pub enum Action {
    GuildUpdate,
    Channel(ActionChannel),
    ChannelOverwrite(ActionChannelOverwrite),
    Member(ActionMember),
    Role(ActionRole),
    Invite(ActionInvite),
    Webhook(ActionWebhook),
    Emoji(ActionEmoji),
    Message(ActionMessage),
    Integration(ActionIntegration),
    StageInstance(ActionStageInstance),
    Sticker(ActionSticker),
    Thread(ActionThread),
}

impl Action {
    pub fn num(self) -> u8 {
        match self {
            Action::GuildUpdate => 1,
            Action::Channel(x) => x as u8,
            Action::ChannelOverwrite(x) => x as u8,
            Action::Member(x) => x as u8,
            Action::Role(x) => x as u8,
            Action::Invite(x) => x as u8,
            Action::Webhook(x) => x as u8,
            Action::Emoji(x) => x as u8,
            Action::Message(x) => x as u8,
            Action::Integration(x) => x as u8,
            Action::StageInstance(x) => x as u8,
            Action::Sticker(x) => x as u8,
            Action::Thread(x) => x as u8,
        }
    }
}

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

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

#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
#[repr(u8)]
pub enum ActionMember {
    Kick = 20,
    Prune = 21,
    BanAdd = 22,
    BanRemove = 23,
    Update = 24,
    RoleUpdate = 25,
    MemberMove = 26,
    MemberDisconnect = 27,
    BotAdd = 28,
}

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

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

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

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

#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
#[repr(u8)]
pub enum ActionMessage {
    Delete = 72,
    BulkDelete = 73,
    Pin = 74,
    Unpin = 75,
}

#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
#[repr(u8)]
pub enum ActionIntegration {
    Create = 80,
    Update = 81,
    Delete = 82,
}

#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
#[repr(u8)]
pub enum ActionStageInstance {
    Create = 83,
    Update = 84,
    Delete = 85,
}

#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
#[repr(u8)]
pub enum ActionSticker {
    Create = 90,
    Update = 91,
    Delete = 92,
}

#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
#[repr(u8)]
pub enum ActionThread {
    Create = 110,
    Update = 111,
    Delete = 112,
}

#[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: Option<Value>,
    #[serde(rename = "new_value")]
    pub new: Option<Value>,
}

#[derive(Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct AuditLogs {
    #[serde(with = "entries", rename = "audit_log_entries")]
    pub entries: HashMap<AuditLogEntryId, AuditLogEntry>,
    pub webhooks: Vec<Webhook>,
    pub users: Vec<User>,
}

mod entries {
    use std::collections::HashMap;

    use serde::Deserializer;

    use super::{AuditLogEntry, AuditLogEntryId};
    use crate::model::utils::SequenceToMapVisitor;

    pub fn deserialize<'de, D: Deserializer<'de>>(
        deserializer: D,
    ) -> Result<HashMap<AuditLogEntryId, AuditLogEntry>, D::Error> {
        deserializer.deserialize_seq(SequenceToMapVisitor::new(|e: &AuditLogEntry| e.id))
    }

    pub use crate::model::utils::serialize_map_values as serialize;
}

#[derive(Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct AuditLogEntry {
    /// Determines to what entity an [`Self::action`] was used on.
    #[serde(with = "option_u64_handler")]
    pub target_id: Option<u64>,
    /// Determines what action was done on a [`Self::target_id`]
    #[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 associated with this entry.
    pub options: Option<Options>,
}

#[derive(Debug, Deserialize, Serialize)]
#[non_exhaustive]
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>,
    /// Message that was pinned or unpinned.
    #[serde(default)]
    pub message_id: Option<MessageId>,
    /// Name of the role if type is "role"
    #[serde(default)]
    pub role_name: Option<String>,
}

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(de::Error::custom)
            }
        }

        des.deserialize_option(OptionU64Visitor)
    }

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

        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..=28 => 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..=75 => Action::Message(unsafe { transmute(value) }),
                    80..=82 => Action::Integration(unsafe { transmute(value) }),
                    83..=85 => Action::StageInstance(unsafe { transmute(value) }),
                    90..=92 => Action::Sticker(unsafe { transmute(value) }),
                    110..=112 => Action::Thread(unsafe { transmute(value) }),
                    _ => 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())
    }
}

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

    #[test]
    fn action_value() {
        macro_rules! assert_action {
            ($action:expr, $num:literal) => {{
                assert_eq!($action.num(), $num);
            }};
        }

        assert_action!(Action::GuildUpdate, 1);
        assert_action!(Action::Channel(ActionChannel::Create), 10);
        assert_action!(Action::Channel(ActionChannel::Update), 11);
        assert_action!(Action::Channel(ActionChannel::Delete), 12);
        assert_action!(Action::ChannelOverwrite(ActionChannelOverwrite::Create), 13);
        assert_action!(Action::ChannelOverwrite(ActionChannelOverwrite::Update), 14);
        assert_action!(Action::ChannelOverwrite(ActionChannelOverwrite::Delete), 15);
        assert_action!(Action::Member(ActionMember::Kick), 20);
        assert_action!(Action::Member(ActionMember::Prune), 21);
        assert_action!(Action::Member(ActionMember::BanAdd), 22);
        assert_action!(Action::Member(ActionMember::BanRemove), 23);
        assert_action!(Action::Member(ActionMember::Update), 24);
        assert_action!(Action::Member(ActionMember::RoleUpdate), 25);
        assert_action!(Action::Member(ActionMember::MemberMove), 26);
        assert_action!(Action::Member(ActionMember::MemberDisconnect), 27);
        assert_action!(Action::Member(ActionMember::BotAdd), 28);
        assert_action!(Action::Role(ActionRole::Create), 30);
        assert_action!(Action::Role(ActionRole::Update), 31);
        assert_action!(Action::Role(ActionRole::Delete), 32);
        assert_action!(Action::Invite(ActionInvite::Create), 40);
        assert_action!(Action::Invite(ActionInvite::Update), 41);
        assert_action!(Action::Invite(ActionInvite::Delete), 42);
        assert_action!(Action::Webhook(ActionWebhook::Create), 50);
        assert_action!(Action::Webhook(ActionWebhook::Update), 51);
        assert_action!(Action::Webhook(ActionWebhook::Delete), 52);
        assert_action!(Action::Emoji(ActionEmoji::Create), 60);
        assert_action!(Action::Emoji(ActionEmoji::Update), 61);
        assert_action!(Action::Emoji(ActionEmoji::Delete), 62);
        assert_action!(Action::Message(ActionMessage::Delete), 72);
        assert_action!(Action::Message(ActionMessage::BulkDelete), 73);
        assert_action!(Action::Message(ActionMessage::Pin), 74);
        assert_action!(Action::Message(ActionMessage::Unpin), 75);
        assert_action!(Action::Integration(ActionIntegration::Create), 80);
        assert_action!(Action::Integration(ActionIntegration::Update), 81);
        assert_action!(Action::Integration(ActionIntegration::Delete), 82);
        assert_action!(Action::StageInstance(ActionStageInstance::Create), 83);
        assert_action!(Action::StageInstance(ActionStageInstance::Update), 84);
        assert_action!(Action::StageInstance(ActionStageInstance::Delete), 85);
        assert_action!(Action::Sticker(ActionSticker::Create), 90);
        assert_action!(Action::Sticker(ActionSticker::Update), 91);
        assert_action!(Action::Sticker(ActionSticker::Delete), 92);
        assert_action!(Action::Thread(ActionThread::Create), 110);
        assert_action!(Action::Thread(ActionThread::Update), 111);
        assert_action!(Action::Thread(ActionThread::Delete), 112);
    }
}
<commit_msg>Implement `serde` traits for the audit `Action` enum directly (#1732)<commit_after>use std::{collections::HashMap, fmt, mem::transmute};

use serde::de::{self, Deserializer, Visitor};
use serde::ser::{Serialize, Serializer};

use crate::model::prelude::*;

/// Determines the action that was done on a target.
#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
pub enum Action {
    GuildUpdate,
    Channel(ActionChannel),
    ChannelOverwrite(ActionChannelOverwrite),
    Member(ActionMember),
    Role(ActionRole),
    Invite(ActionInvite),
    Webhook(ActionWebhook),
    Emoji(ActionEmoji),
    Message(ActionMessage),
    Integration(ActionIntegration),
    StageInstance(ActionStageInstance),
    Sticker(ActionSticker),
    Thread(ActionThread),
}

impl Action {
    pub fn num(self) -> u8 {
        match self {
            Action::GuildUpdate => 1,
            Action::Channel(x) => x as u8,
            Action::ChannelOverwrite(x) => x as u8,
            Action::Member(x) => x as u8,
            Action::Role(x) => x as u8,
            Action::Invite(x) => x as u8,
            Action::Webhook(x) => x as u8,
            Action::Emoji(x) => x as u8,
            Action::Message(x) => x as u8,
            Action::Integration(x) => x as u8,
            Action::StageInstance(x) => x as u8,
            Action::Sticker(x) => x as u8,
            Action::Thread(x) => x as u8,
        }
    }

    pub fn from_value(value: u8) -> Option<Action> {
        let action = match value {
            1 => Action::GuildUpdate,
            10..=12 => Action::Channel(unsafe { transmute(value) }),
            13..=15 => Action::ChannelOverwrite(unsafe { transmute(value) }),
            20..=28 => 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..=75 => Action::Message(unsafe { transmute(value) }),
            80..=82 => Action::Integration(unsafe { transmute(value) }),
            83..=85 => Action::StageInstance(unsafe { transmute(value) }),
            90..=92 => Action::Sticker(unsafe { transmute(value) }),
            110..=112 => Action::Thread(unsafe { transmute(value) }),
            _ => return None,
        };

        Some(action)
    }
}

impl<'de> Deserialize<'de> for Action {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
        let value = u8::deserialize(deserializer)?;
        Action::from_value(value)
            .ok_or_else(|| de::Error::custom(format!("Unexpected action number: {}", value)))
    }
}

impl Serialize for Action {
    fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
        serializer.serialize_u8(self.num())
    }
}

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

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

#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
#[repr(u8)]
pub enum ActionMember {
    Kick = 20,
    Prune = 21,
    BanAdd = 22,
    BanRemove = 23,
    Update = 24,
    RoleUpdate = 25,
    MemberMove = 26,
    MemberDisconnect = 27,
    BotAdd = 28,
}

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

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

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

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

#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
#[repr(u8)]
pub enum ActionMessage {
    Delete = 72,
    BulkDelete = 73,
    Pin = 74,
    Unpin = 75,
}

#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
#[repr(u8)]
pub enum ActionIntegration {
    Create = 80,
    Update = 81,
    Delete = 82,
}

#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
#[repr(u8)]
pub enum ActionStageInstance {
    Create = 83,
    Update = 84,
    Delete = 85,
}

#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
#[repr(u8)]
pub enum ActionSticker {
    Create = 90,
    Update = 91,
    Delete = 92,
}

#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
#[repr(u8)]
pub enum ActionThread {
    Create = 110,
    Update = 111,
    Delete = 112,
}

#[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: Option<Value>,
    #[serde(rename = "new_value")]
    pub new: Option<Value>,
}

#[derive(Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct AuditLogs {
    #[serde(with = "entries", rename = "audit_log_entries")]
    pub entries: HashMap<AuditLogEntryId, AuditLogEntry>,
    pub webhooks: Vec<Webhook>,
    pub users: Vec<User>,
}

mod entries {
    use std::collections::HashMap;

    use serde::Deserializer;

    use super::{AuditLogEntry, AuditLogEntryId};
    use crate::model::utils::SequenceToMapVisitor;

    pub fn deserialize<'de, D: Deserializer<'de>>(
        deserializer: D,
    ) -> Result<HashMap<AuditLogEntryId, AuditLogEntry>, D::Error> {
        deserializer.deserialize_seq(SequenceToMapVisitor::new(|e: &AuditLogEntry| e.id))
    }

    pub use crate::model::utils::serialize_map_values as serialize;
}

#[derive(Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct AuditLogEntry {
    /// Determines to what entity an [`Self::action`] was used on.
    #[serde(with = "option_u64_handler")]
    pub target_id: Option<u64>,
    /// Determines what action was done on a [`Self::target_id`]
    #[serde(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 associated with this entry.
    pub options: Option<Options>,
}

#[derive(Debug, Deserialize, Serialize)]
#[non_exhaustive]
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>,
    /// Message that was pinned or unpinned.
    #[serde(default)]
    pub message_id: Option<MessageId>,
    /// Name of the role if type is "role"
    #[serde(default)]
    pub role_name: Option<String>,
}

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(de::Error::custom)
            }
        }

        des.deserialize_option(OptionU64Visitor)
    }

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

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

    #[test]
    fn action_value() {
        macro_rules! assert_action {
            ($action:pat, $num:literal) => {{
                let a = Action::from_value($num).expect("invalid action value");
                assert!(matches!(a, $action), "{:?} didn't match the variant", a);
                assert_eq!(a.num(), $num);
            }};
        }

        assert_action!(Action::GuildUpdate, 1);
        assert_action!(Action::Channel(ActionChannel::Create), 10);
        assert_action!(Action::Channel(ActionChannel::Update), 11);
        assert_action!(Action::Channel(ActionChannel::Delete), 12);
        assert_action!(Action::ChannelOverwrite(ActionChannelOverwrite::Create), 13);
        assert_action!(Action::ChannelOverwrite(ActionChannelOverwrite::Update), 14);
        assert_action!(Action::ChannelOverwrite(ActionChannelOverwrite::Delete), 15);
        assert_action!(Action::Member(ActionMember::Kick), 20);
        assert_action!(Action::Member(ActionMember::Prune), 21);
        assert_action!(Action::Member(ActionMember::BanAdd), 22);
        assert_action!(Action::Member(ActionMember::BanRemove), 23);
        assert_action!(Action::Member(ActionMember::Update), 24);
        assert_action!(Action::Member(ActionMember::RoleUpdate), 25);
        assert_action!(Action::Member(ActionMember::MemberMove), 26);
        assert_action!(Action::Member(ActionMember::MemberDisconnect), 27);
        assert_action!(Action::Member(ActionMember::BotAdd), 28);
        assert_action!(Action::Role(ActionRole::Create), 30);
        assert_action!(Action::Role(ActionRole::Update), 31);
        assert_action!(Action::Role(ActionRole::Delete), 32);
        assert_action!(Action::Invite(ActionInvite::Create), 40);
        assert_action!(Action::Invite(ActionInvite::Update), 41);
        assert_action!(Action::Invite(ActionInvite::Delete), 42);
        assert_action!(Action::Webhook(ActionWebhook::Create), 50);
        assert_action!(Action::Webhook(ActionWebhook::Update), 51);
        assert_action!(Action::Webhook(ActionWebhook::Delete), 52);
        assert_action!(Action::Emoji(ActionEmoji::Create), 60);
        assert_action!(Action::Emoji(ActionEmoji::Update), 61);
        assert_action!(Action::Emoji(ActionEmoji::Delete), 62);
        assert_action!(Action::Message(ActionMessage::Delete), 72);
        assert_action!(Action::Message(ActionMessage::BulkDelete), 73);
        assert_action!(Action::Message(ActionMessage::Pin), 74);
        assert_action!(Action::Message(ActionMessage::Unpin), 75);
        assert_action!(Action::Integration(ActionIntegration::Create), 80);
        assert_action!(Action::Integration(ActionIntegration::Update), 81);
        assert_action!(Action::Integration(ActionIntegration::Delete), 82);
        assert_action!(Action::StageInstance(ActionStageInstance::Create), 83);
        assert_action!(Action::StageInstance(ActionStageInstance::Update), 84);
        assert_action!(Action::StageInstance(ActionStageInstance::Delete), 85);
        assert_action!(Action::Sticker(ActionSticker::Create), 90);
        assert_action!(Action::Sticker(ActionSticker::Update), 91);
        assert_action!(Action::Sticker(ActionSticker::Delete), 92);
        assert_action!(Action::Thread(ActionThread::Create), 110);
        assert_action!(Action::Thread(ActionThread::Update), 111);
        assert_action!(Action::Thread(ActionThread::Delete), 112);
    }
}
<|endoftext|>


<commit_before>use std::{collections::HashMap, fmt, mem::transmute};

use serde::de::{self, Deserializer, Visitor};
use serde::ser::Serializer;

use crate::internal::prelude::*;
use crate::model::prelude::*;

/// Determines the action that was done on a target.
#[derive(Debug)]
#[non_exhaustive]
pub enum Action {
    GuildUpdate,
    Channel(ActionChannel),
    ChannelOverwrite(ActionChannelOverwrite),
    Member(ActionMember),
    Role(ActionRole),
    Invite(ActionInvite),
    Webhook(ActionWebhook),
    Emoji(ActionEmoji),
    Message(ActionMessage),
    Integration(ActionIntegration),
    StageInstance(ActionStageInstance),
    Sticker(ActionSticker),
    Thread(ActionThread),
}

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::Message(ref x) => x.num(),
            Action::Integration(ref x) => x.num(),
            Action::StageInstance(ref x) => x.num(),
            Action::Sticker(ref x) => x.num(),
            Action::Thread(ref x) => x.num(),
        }
    }
}

#[derive(Debug)]
#[non_exhaustive]
#[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)]
#[non_exhaustive]
#[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)]
#[non_exhaustive]
#[repr(u8)]
pub enum ActionMember {
    Kick = 20,
    Prune = 21,
    BanAdd = 22,
    BanRemove = 23,
    Update = 24,
    RoleUpdate = 25,
    MemberMove = 26,
    MemberDisconnect = 27,
    BotAdd = 28,
}

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,
            ActionMember::MemberMove => 26,
            ActionMember::MemberDisconnect => 27,
            ActionMember::BotAdd => 28,
        }
    }
}

#[derive(Debug)]
#[non_exhaustive]
#[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)]
#[non_exhaustive]
#[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)]
#[non_exhaustive]
#[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)]
#[non_exhaustive]
#[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)]
#[non_exhaustive]
#[repr(u8)]
pub enum ActionMessage {
    Delete = 72,
    BulkDelete = 73,
    Pin = 74,
    Unpin = 75,
}

impl ActionMessage {
    pub fn num(&self) -> u8 {
        match *self {
            ActionMessage::Delete => 72,
            ActionMessage::BulkDelete => 73,
            ActionMessage::Pin => 74,
            ActionMessage::Unpin => 75,
        }
    }
}

#[derive(Debug)]
#[non_exhaustive]
#[repr(u8)]
pub enum ActionIntegration {
    Create = 80,
    Update = 81,
    Delete = 82,
}

impl ActionIntegration {
    pub fn num(&self) -> u8 {
        match *self {
            ActionIntegration::Create => 80,
            ActionIntegration::Update => 81,
            ActionIntegration::Delete => 82,
        }
    }
}

#[derive(Debug)]
#[non_exhaustive]
#[repr(u8)]
pub enum ActionStageInstance {
    Create = 83,
    Update = 84,
    Delete = 85,
}

impl ActionStageInstance {
    pub fn num(&self) -> u8 {
        match *self {
            ActionStageInstance::Create => 83,
            ActionStageInstance::Update => 84,
            ActionStageInstance::Delete => 85,
        }
    }
}

#[derive(Debug)]
#[non_exhaustive]
#[repr(u8)]
pub enum ActionSticker {
    Create = 90,
    Update = 91,
    Delete = 92,
}

impl ActionSticker {
    pub fn num(&self) -> u8 {
        match *self {
            ActionSticker::Create => 90,
            ActionSticker::Update => 91,
            ActionSticker::Delete => 92,
        }
    }
}

#[derive(Debug)]
#[non_exhaustive]
#[repr(u8)]
pub enum ActionThread {
    Create = 110,
    Update = 111,
    Delete = 112,
}

impl ActionThread {
    pub fn num(&self) -> u8 {
        match *self {
            ActionThread::Create => 110,
            ActionThread::Update => 111,
            ActionThread::Delete => 112,
        }
    }
}

#[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: Option<Value>,
    #[serde(rename = "new_value")]
    pub new: Option<Value>,
}

#[derive(Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct AuditLogs {
    #[serde(with = "entries", rename = "audit_log_entries")]
    pub entries: HashMap<AuditLogEntryId, AuditLogEntry>,
    pub webhooks: Vec<Webhook>,
    pub users: Vec<User>,
}

mod entries {
    use std::collections::HashMap;

    use serde::Deserializer;

    use super::{AuditLogEntry, AuditLogEntryId};
    use crate::model::utils::SequenceToMapVisitor;

    pub fn deserialize<'de, D: Deserializer<'de>>(
        deserializer: D,
    ) -> Result<HashMap<AuditLogEntryId, AuditLogEntry>, D::Error> {
        deserializer.deserialize_seq(SequenceToMapVisitor::new(|e: &AuditLogEntry| e.id))
    }

    pub use crate::model::utils::serialize_map_values as serialize;
}

#[derive(Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct AuditLogEntry {
    /// Determines to what entity an [`Self::action`] was used on.
    #[serde(with = "option_u64_handler")]
    pub target_id: Option<u64>,
    /// Determines what action was done on a [`Self::target_id`]
    #[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 associated with this entry.
    pub options: Option<Options>,
}

#[derive(Debug, Deserialize, Serialize)]
#[non_exhaustive]
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>,
    /// Message that was pinned or unpinned.
    #[serde(default)]
    pub message_id: Option<MessageId>,
    /// Name of the role if type is "role"
    #[serde(default)]
    pub role_name: Option<String>,
}

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(de::Error::custom)
            }
        }

        des.deserialize_option(OptionU64Visitor)
    }

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

        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..=28 => 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..=75 => Action::Message(unsafe { transmute(value) }),
                    80..=82 => Action::Integration(unsafe { transmute(value) }),
                    83..=85 => Action::StageInstance(unsafe { transmute(value) }),
                    90..=92 => Action::Sticker(unsafe { transmute(value) }),
                    110..=112 => Action::Thread(unsafe { transmute(value) }),
                    _ => 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())
    }
}
<commit_msg>Derive `Copy` and `Clone` traits for the audit action enums (#1731)<commit_after>use std::{collections::HashMap, fmt, mem::transmute};

use serde::de::{self, Deserializer, Visitor};
use serde::ser::Serializer;

use crate::internal::prelude::*;
use crate::model::prelude::*;

/// Determines the action that was done on a target.
#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
pub enum Action {
    GuildUpdate,
    Channel(ActionChannel),
    ChannelOverwrite(ActionChannelOverwrite),
    Member(ActionMember),
    Role(ActionRole),
    Invite(ActionInvite),
    Webhook(ActionWebhook),
    Emoji(ActionEmoji),
    Message(ActionMessage),
    Integration(ActionIntegration),
    StageInstance(ActionStageInstance),
    Sticker(ActionSticker),
    Thread(ActionThread),
}

impl Action {
    pub fn num(self) -> u8 {
        match self {
            Action::GuildUpdate => 1,
            Action::Channel(x) => x as u8,
            Action::ChannelOverwrite(x) => x as u8,
            Action::Member(x) => x as u8,
            Action::Role(x) => x as u8,
            Action::Invite(x) => x as u8,
            Action::Webhook(x) => x as u8,
            Action::Emoji(x) => x as u8,
            Action::Message(x) => x as u8,
            Action::Integration(x) => x as u8,
            Action::StageInstance(x) => x as u8,
            Action::Sticker(x) => x as u8,
            Action::Thread(x) => x as u8,
        }
    }
}

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

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

#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
#[repr(u8)]
pub enum ActionMember {
    Kick = 20,
    Prune = 21,
    BanAdd = 22,
    BanRemove = 23,
    Update = 24,
    RoleUpdate = 25,
    MemberMove = 26,
    MemberDisconnect = 27,
    BotAdd = 28,
}

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

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

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

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

#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
#[repr(u8)]
pub enum ActionMessage {
    Delete = 72,
    BulkDelete = 73,
    Pin = 74,
    Unpin = 75,
}

#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
#[repr(u8)]
pub enum ActionIntegration {
    Create = 80,
    Update = 81,
    Delete = 82,
}

#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
#[repr(u8)]
pub enum ActionStageInstance {
    Create = 83,
    Update = 84,
    Delete = 85,
}

#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
#[repr(u8)]
pub enum ActionSticker {
    Create = 90,
    Update = 91,
    Delete = 92,
}

#[derive(Copy, Clone, Debug)]
#[non_exhaustive]
#[repr(u8)]
pub enum ActionThread {
    Create = 110,
    Update = 111,
    Delete = 112,
}

#[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: Option<Value>,
    #[serde(rename = "new_value")]
    pub new: Option<Value>,
}

#[derive(Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct AuditLogs {
    #[serde(with = "entries", rename = "audit_log_entries")]
    pub entries: HashMap<AuditLogEntryId, AuditLogEntry>,
    pub webhooks: Vec<Webhook>,
    pub users: Vec<User>,
}

mod entries {
    use std::collections::HashMap;

    use serde::Deserializer;

    use super::{AuditLogEntry, AuditLogEntryId};
    use crate::model::utils::SequenceToMapVisitor;

    pub fn deserialize<'de, D: Deserializer<'de>>(
        deserializer: D,
    ) -> Result<HashMap<AuditLogEntryId, AuditLogEntry>, D::Error> {
        deserializer.deserialize_seq(SequenceToMapVisitor::new(|e: &AuditLogEntry| e.id))
    }

    pub use crate::model::utils::serialize_map_values as serialize;
}

#[derive(Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct AuditLogEntry {
    /// Determines to what entity an [`Self::action`] was used on.
    #[serde(with = "option_u64_handler")]
    pub target_id: Option<u64>,
    /// Determines what action was done on a [`Self::target_id`]
    #[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 associated with this entry.
    pub options: Option<Options>,
}

#[derive(Debug, Deserialize, Serialize)]
#[non_exhaustive]
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>,
    /// Message that was pinned or unpinned.
    #[serde(default)]
    pub message_id: Option<MessageId>,
    /// Name of the role if type is "role"
    #[serde(default)]
    pub role_name: Option<String>,
}

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(de::Error::custom)
            }
        }

        des.deserialize_option(OptionU64Visitor)
    }

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

        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..=28 => 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..=75 => Action::Message(unsafe { transmute(value) }),
                    80..=82 => Action::Integration(unsafe { transmute(value) }),
                    83..=85 => Action::StageInstance(unsafe { transmute(value) }),
                    90..=92 => Action::Sticker(unsafe { transmute(value) }),
                    110..=112 => Action::Thread(unsafe { transmute(value) }),
                    _ => 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())
    }
}

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

    #[test]
    fn action_value() {
        macro_rules! assert_action {
            ($action:expr, $num:literal) => {{
                assert_eq!($action.num(), $num);
            }};
        }

        assert_action!(Action::GuildUpdate, 1);
        assert_action!(Action::Channel(ActionChannel::Create), 10);
        assert_action!(Action::Channel(ActionChannel::Update), 11);
        assert_action!(Action::Channel(ActionChannel::Delete), 12);
        assert_action!(Action::ChannelOverwrite(ActionChannelOverwrite::Create), 13);
        assert_action!(Action::ChannelOverwrite(ActionChannelOverwrite::Update), 14);
        assert_action!(Action::ChannelOverwrite(ActionChannelOverwrite::Delete), 15);
        assert_action!(Action::Member(ActionMember::Kick), 20);
        assert_action!(Action::Member(ActionMember::Prune), 21);
        assert_action!(Action::Member(ActionMember::BanAdd), 22);
        assert_action!(Action::Member(ActionMember::BanRemove), 23);
        assert_action!(Action::Member(ActionMember::Update), 24);
        assert_action!(Action::Member(ActionMember::RoleUpdate), 25);
        assert_action!(Action::Member(ActionMember::MemberMove), 26);
        assert_action!(Action::Member(ActionMember::MemberDisconnect), 27);
        assert_action!(Action::Member(ActionMember::BotAdd), 28);
        assert_action!(Action::Role(ActionRole::Create), 30);
        assert_action!(Action::Role(ActionRole::Update), 31);
        assert_action!(Action::Role(ActionRole::Delete), 32);
        assert_action!(Action::Invite(ActionInvite::Create), 40);
        assert_action!(Action::Invite(ActionInvite::Update), 41);
        assert_action!(Action::Invite(ActionInvite::Delete), 42);
        assert_action!(Action::Webhook(ActionWebhook::Create), 50);
        assert_action!(Action::Webhook(ActionWebhook::Update), 51);
        assert_action!(Action::Webhook(ActionWebhook::Delete), 52);
        assert_action!(Action::Emoji(ActionEmoji::Create), 60);
        assert_action!(Action::Emoji(ActionEmoji::Update), 61);
        assert_action!(Action::Emoji(ActionEmoji::Delete), 62);
        assert_action!(Action::Message(ActionMessage::Delete), 72);
        assert_action!(Action::Message(ActionMessage::BulkDelete), 73);
        assert_action!(Action::Message(ActionMessage::Pin), 74);
        assert_action!(Action::Message(ActionMessage::Unpin), 75);
        assert_action!(Action::Integration(ActionIntegration::Create), 80);
        assert_action!(Action::Integration(ActionIntegration::Update), 81);
        assert_action!(Action::Integration(ActionIntegration::Delete), 82);
        assert_action!(Action::StageInstance(ActionStageInstance::Create), 83);
        assert_action!(Action::StageInstance(ActionStageInstance::Update), 84);
        assert_action!(Action::StageInstance(ActionStageInstance::Delete), 85);
        assert_action!(Action::Sticker(ActionSticker::Create), 90);
        assert_action!(Action::Sticker(ActionSticker::Update), 91);
        assert_action!(Action::Sticker(ActionSticker::Delete), 92);
        assert_action!(Action::Thread(ActionThread::Create), 110);
        assert_action!(Action::Thread(ActionThread::Update), 111);
        assert_action!(Action::Thread(ActionThread::Delete), 112);
    }
}
<|endoftext|>


<commit_before>pub struct SubFrame {
  pub data: Data,
  pub wasted_bits: u32,
}

pub enum Data {
  Constant(i32),
  Verbatim(Vec<i32>),
}
<commit_msg>Add types for the `Fixed` subframe data<commit_after>pub const MAX_FIXED_ORDER: usize = 4;

pub struct SubFrame {
  pub data: Data,
  pub wasted_bits: u32,
}

pub enum Data {
  Constant(i32),
  Verbatim(Vec<i32>),
  Fixed(Fixed),
}

pub struct Fixed {
  pub entropy_coding_method: EntropyCodingMethod,
  pub order: u8,
  pub warmup: [i32; MAX_FIXED_ORDER],
  pub residual: Vec<i32>,
}

pub struct EntropyCodingMethod {
  pub method_type: CodingMethod,
  pub data: PartitionedRice,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum CodingMethod {
  PartitionedRice,
  PartitionedRice2,
}

pub struct PartitionedRice {
  pub order: u32,
  pub contents: PartitionedRiceContents,
}

pub struct PartitionedRiceContents {
  pub parameters: Vec<u32>,
  pub raw_bits: Vec<u32>,
  pub capacity_by_order: u32,
}
<|endoftext|>


<commit_before>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

/// A single token representing a Markdown element.
///
/// A Markdown document is, thus, a Vec of `Token`s.
#[derive(Debug, PartialEq, Clone)]
pub enum Token {
    /// The most simple element, containing a String
    Str(String),
    /// A paragraph, containing a list of elements
    Paragraph(Vec<Token>),
    /// A header with a header number and the title
    Header(i32, Vec<Token>),
    /// *Emphasis*, a.k.a. italics
    Emphasis(Vec<Token>),
    /// **Strong**, a.k.a. bold
    Strong(Vec<Token>),
    /// `Code`, a.k.a. verbatim
    Code(Vec<Token>),
    /// A quote
    BlockQuote(Vec<Token>),
    /// Code block with language and content
    CodeBlock(String, Vec<Token>),

    /// Unordered list, with a vector of `Item`s
    List(Vec<Token>),
    /// Ordered list, with a starting number, and a list of `Item`s
    OrderedList(usize, Vec<Token>),
    /// Item of a list
    Item(Vec<Token>),

    /// Table with number of rows, and a list of `TableHead` and `TableRows`
    Table(i32, Vec<Token>),
    /// Table header, contains `TableCell`s
    TableHead(Vec<Token>),
    /// Row of a table, contains `TableCell`s
    TableRow(Vec<Token>),
    /// Cell of a table
    TableCell(Vec<Token>),

    /// A footnote, contains the content it is pointing to.
    Footnote(Vec<Token>),

    /// Horizontal rule
    Rule,
    /// Softbreak, usually rendered by a space
    SoftBreak,
    /// Hardbreak
    HardBreak,

    /// A link with an url, a title, and the linked text
    Link(String, String, Vec<Token>),
    /// An image with a source url, a title and an alt tex
    Image(String, String, Vec<Token>),
    /// Similar to previous, but when image is in a standalone paragraph
    StandaloneImage(String, String, Vec<Token>),
}

use Token::*;

impl Token {
    /// Returns the inner list of tokens contained in this token (if any)
    pub fn inner(&self) -> Option<&[Token]> {
        match *self {
            Rule
                | SoftBreak
                | HardBreak
                | Str(_) => None,
            Paragraph(ref v)
                | Header(_, ref v)
                | Emphasis(ref v)
                | Strong(ref v)
                | Code(ref v)
                | BlockQuote(ref v)
                | CodeBlock(_, ref v)
                | List(ref v)
                | OrderedList(_, ref v)
                | Item(ref v)
                | Table(_, ref v)
                | TableHead(ref v)
                | TableRow(ref v)
                | TableCell(ref v)
                | Footnote(ref v)
                | Link(_,_,ref v)
                | Image(_,_,ref v)
                | StandaloneImage(_,_,ref v) => Some(v)
        }
    }

    /// Returns the inner list of tokens contained in this token (if any) (mutable version)
    pub fn inner_mut(&mut self) -> Option<&mut Vec<Token>> {
        match *self {
            Rule
                | SoftBreak
                | HardBreak
                | Str(_) => None,
            Paragraph(ref mut v)
                | Header(_, ref mut v)
                | Emphasis(ref mut v)
                | Strong(ref mut v)
                | Code(ref mut v)
                | BlockQuote(ref mut v)
                | CodeBlock(_, ref mut v)
                | List(ref mut v)
                | OrderedList(_, ref mut v)
                | Item(ref mut v)
                | Table(_, ref mut v)
                | TableHead(ref mut v)
                | TableRow(ref mut v)
                | TableCell(ref mut v)
                | Footnote(ref mut v)
                | Link(_,_,ref mut v)
                | Image(_,_,ref mut v)
                | StandaloneImage(_,_,ref mut v) => Some(v)
        }
    }

    /// Checks whether token is an str
    pub fn is_str(&self) -> bool {
        if let Token::Str(_) = *self { true } else { false }
    }

    /// Checks whether token is an image
    ///
    /// **Returns** `true` if and only if token is Image variant (StandaloneImage returns *false*, like other variants)
    pub fn is_image(&self) -> bool {
        if let Token::Image(_, _, _) = *self { true } else { false }
    }
}

<commit_msg>Fix formatting<commit_after>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

/// A single token representing a Markdown element.
///
/// A Markdown document is, thus, a Vec of `Token`s.
#[derive(Debug, PartialEq, Clone)]
pub enum Token {
    /// The most simple element, containing a String
    Str(String),
    /// A paragraph, containing a list of elements
    Paragraph(Vec<Token>),
    /// A header with a header number and the title
    Header(i32, Vec<Token>),
    /// *Emphasis*, a.k.a. italics
    Emphasis(Vec<Token>),
    /// **Strong**, a.k.a. bold
    Strong(Vec<Token>),
    /// `Code`, a.k.a. verbatim
    Code(Vec<Token>),
    /// A quote
    BlockQuote(Vec<Token>),
    /// Code block with language and content
    CodeBlock(String, Vec<Token>),

    /// Unordered list, with a vector of `Item`s
    List(Vec<Token>),
    /// Ordered list, with a starting number, and a list of `Item`s
    OrderedList(usize, Vec<Token>),
    /// Item of a list
    Item(Vec<Token>),

    /// Table with number of rows, and a list of `TableHead` and `TableRows`
    Table(i32, Vec<Token>),
    /// Table header, contains `TableCell`s
    TableHead(Vec<Token>),
    /// Row of a table, contains `TableCell`s
    TableRow(Vec<Token>),
    /// Cell of a table
    TableCell(Vec<Token>),

    /// A footnote, contains the content it is pointing to.
    Footnote(Vec<Token>),

    /// Horizontal rule
    Rule,
    /// Softbreak, usually rendered by a space
    SoftBreak,
    /// Hardbreak
    HardBreak,

    /// A link with an url, a title, and the linked text
    Link(String, String, Vec<Token>),
    /// An image with a source url, a title and an alt tex
    Image(String, String, Vec<Token>),
    /// Similar to previous, but when image is in a standalone paragraph
    StandaloneImage(String, String, Vec<Token>),
}

use Token::*;

impl Token {
    /// Returns the inner list of tokens contained in this token (if any)
    pub fn inner(&self) -> Option<&[Token]> {
        match *self {
            Rule
                | SoftBreak
                | HardBreak
                | Str(_)
                => None,

            Paragraph(ref v)
                | Header(_, ref v)
                | Emphasis(ref v)
                | Strong(ref v)
                | Code(ref v)
                | BlockQuote(ref v)
                | CodeBlock(_, ref v)
                | List(ref v)
                | OrderedList(_, ref v)
                | Item(ref v)
                | Table(_, ref v)
                | TableHead(ref v)
                | TableRow(ref v)
                | TableCell(ref v)
                | Footnote(ref v)
                | Link(_,_,ref v)
                | Image(_,_,ref v)
                | StandaloneImage(_,_,ref v)
                => Some(v)
        }
    }

    /// Returns the inner list of tokens contained in this token (if any) (mutable version)
    pub fn inner_mut(&mut self) -> Option<&mut Vec<Token>> {
        match *self {
            Rule
                | SoftBreak
                | HardBreak
                | Str(_)
                => None,

            Paragraph(ref mut v)
                | Header(_, ref mut v)
                | Emphasis(ref mut v)
                | Strong(ref mut v)
                | Code(ref mut v)
                | BlockQuote(ref mut v)
                | CodeBlock(_, ref mut v)
                | List(ref mut v)
                | OrderedList(_, ref mut v)
                | Item(ref mut v)
                | Table(_, ref mut v)
                | TableHead(ref mut v)
                | TableRow(ref mut v)
                | TableCell(ref mut v)
                | Footnote(ref mut v)
                | Link(_,_,ref mut v)
                | Image(_,_,ref mut v)
                | StandaloneImage(_,_,ref mut v)
                => Some(v)
        }
    }

    /// Checks whether token is an str
    pub fn is_str(&self) -> bool {
        if let Token::Str(_) = *self { true } else { false }
    }

    /// Checks whether token is an image
    ///
    /// **Returns** `true` if and only if token is Image variant (StandaloneImage returns *false*, like other variants)
    pub fn is_image(&self) -> bool {
        if let Token::Image(_, _, _) = *self { true } else { false }
    }
}

<|endoftext|>


<commit_before>use crate::{frame::Frame, packer::Packer, rect::Rect, texture_packer_config::TexturePackerConfig};
use std::cmp::max;

struct Skyline {
    pub x: u32,
    pub y: u32,
    pub w: u32,
}

impl Skyline {
    #[inline(always)]
    pub fn left(&self) -> u32 {
        self.x
    }

    #[inline(always)]
    pub fn right(&self) -> u32 {
        self.x + self.w - 1
    }
}

pub struct SkylinePacker {
    config: TexturePackerConfig,
    border: Rect,

    // the skylines are sorted by their `x` position
    skylines: Vec<Skyline>,
}

impl SkylinePacker {
    pub fn new(config: TexturePackerConfig) -> Self {
        let mut skylines = Vec::new();
        skylines.push(Skyline {
            x: 0,
            y: 0,
            w: config.max_width,
        });

        SkylinePacker {
            config,
            border: Rect::new(0, 0, config.max_width, config.max_height),
            skylines,
        }
    }

    // return `rect` if rectangle (w, h) can fit the skyline started at `i`
    fn can_put(&self, mut i: usize, w: u32, h: u32) -> Option<Rect> {
        let mut rect = Rect::new(self.skylines[i].x, 0, w, h);
        let mut width_left = rect.w;
        loop {
            rect.y = max(rect.y, self.skylines[i].y);
            // the source rect is too large
            if !self.border.contains(&rect) {
                return None;
            }
            if self.skylines[i].w >= width_left {
                return Some(rect);
            }
            width_left -= self.skylines[i].w;
            i += 1;
            assert!(i < self.skylines.len());
        }
    }

    fn find_skyline(&self, w: u32, h: u32) -> Option<(usize, Rect)> {
        let mut bottom = std::u32::MAX;
        let mut width = std::u32::MAX;
        let mut index = None;
        let mut rect = Rect::new(0, 0, 0, 0);

        // keep the `bottom` and `width` as small as possible
        for i in 0..self.skylines.len() {
            if let Some(r) = self.can_put(i, w, h) {
                if r.bottom() < bottom || (r.bottom() == bottom && self.skylines[i].w < width) {
                    bottom = r.bottom();
                    width = self.skylines[i].w;
                    index = Some(i);
                    rect = r;
                }
            }

            if self.config.allow_rotation {
                if let Some(r) = self.can_put(i, h, w) {
                    if r.bottom() < bottom || (r.bottom() == bottom && self.skylines[i].w < width) {
                        bottom = r.bottom();
                        width = self.skylines[i].w;
                        index = Some(i);
                        rect = r;
                    }
                }
            }
        }

        if let Some(index) = index {
            Some((index, rect))
        } else {
            None
        }
    }

    fn split(&mut self, index: usize, rect: &Rect) {
        let skyline = Skyline {
            x: rect.left(),
            y: rect.bottom() + 1,
            w: rect.w,
        };

        assert!(skyline.right() <= self.border.right());
        assert!(skyline.y <= self.border.bottom());

        self.skylines.insert(index, skyline);

        let i = index + 1;
        while i < self.skylines.len() {
            assert!(self.skylines[i - 1].left() <= self.skylines[i].left());

            if self.skylines[i].left() <= self.skylines[i - 1].right() {
                let shrink = self.skylines[i - 1].right() - self.skylines[i].left() + 1;
                if self.skylines[i].w <= shrink {
                    self.skylines.remove(i);
                } else {
                    self.skylines[i].x += shrink;
                    self.skylines[i].w -= shrink;
                    break;
                }
            } else {
                break;
            }
        }
    }

    fn merge(&mut self) {
        let mut i = 1;
        while i < self.skylines.len() {
            if self.skylines[i - 1].y == self.skylines[i].y {
                self.skylines[i - 1].w += self.skylines[i].w;
                self.skylines.remove(i);
                i -= 1;
            }
            i += 1;
        }
    }
}

impl Packer for SkylinePacker {
    fn pack(&mut self, key: String, texture_rect: &Rect) -> Option<Frame> {
        let mut width = texture_rect.w;
        let mut height = texture_rect.h;

        width += self.config.texture_padding;
        height += self.config.texture_padding;

        if let Some((i, mut rect)) = self.find_skyline(width, height) {
            self.split(i, &rect);
            self.merge();

            let rotated = width != rect.w;

            rect.w -= self.config.texture_padding;
            rect.h -= self.config.texture_padding;

            Some(Frame {
                key,
                frame: rect,
                rotated,
                trimmed: false,
                source: Rect {
                    x: 0,
                    y: 0,
                    w: texture_rect.w,
                    h: texture_rect.h,
                },
            })
        } else {
            None
        }
    }

    fn can_pack(&self, texture_rect: &Rect) -> bool {
        if let Some((_, rect)) = self.find_skyline(
            texture_rect.w + self.config.texture_padding,
            texture_rect.h + self.config.texture_padding,
        ) {
            let skyline = Skyline {
                x: rect.left(),
                y: rect.bottom() + 1,
                w: rect.w,
            };

            return skyline.right() <= self.border.right() && skyline.y <= self.border.bottom();
        }
        false
    }
}
<commit_msg>Shorten if-else on an option to just a map<commit_after>use crate::{frame::Frame, packer::Packer, rect::Rect, texture_packer_config::TexturePackerConfig};
use std::cmp::max;

struct Skyline {
    pub x: u32,
    pub y: u32,
    pub w: u32,
}

impl Skyline {
    #[inline(always)]
    pub fn left(&self) -> u32 {
        self.x
    }

    #[inline(always)]
    pub fn right(&self) -> u32 {
        self.x + self.w - 1
    }
}

pub struct SkylinePacker {
    config: TexturePackerConfig,
    border: Rect,

    // the skylines are sorted by their `x` position
    skylines: Vec<Skyline>,
}

impl SkylinePacker {
    pub fn new(config: TexturePackerConfig) -> Self {
        let mut skylines = Vec::new();
        skylines.push(Skyline {
            x: 0,
            y: 0,
            w: config.max_width,
        });

        SkylinePacker {
            config,
            border: Rect::new(0, 0, config.max_width, config.max_height),
            skylines,
        }
    }

    // return `rect` if rectangle (w, h) can fit the skyline started at `i`
    fn can_put(&self, mut i: usize, w: u32, h: u32) -> Option<Rect> {
        let mut rect = Rect::new(self.skylines[i].x, 0, w, h);
        let mut width_left = rect.w;
        loop {
            rect.y = max(rect.y, self.skylines[i].y);
            // the source rect is too large
            if !self.border.contains(&rect) {
                return None;
            }
            if self.skylines[i].w >= width_left {
                return Some(rect);
            }
            width_left -= self.skylines[i].w;
            i += 1;
            assert!(i < self.skylines.len());
        }
    }

    fn find_skyline(&self, w: u32, h: u32) -> Option<(usize, Rect)> {
        let mut bottom = std::u32::MAX;
        let mut width = std::u32::MAX;
        let mut index = None;
        let mut rect = Rect::new(0, 0, 0, 0);

        // keep the `bottom` and `width` as small as possible
        for i in 0..self.skylines.len() {
            if let Some(r) = self.can_put(i, w, h) {
                if r.bottom() < bottom || (r.bottom() == bottom && self.skylines[i].w < width) {
                    bottom = r.bottom();
                    width = self.skylines[i].w;
                    index = Some(i);
                    rect = r;
                }
            }

            if self.config.allow_rotation {
                if let Some(r) = self.can_put(i, h, w) {
                    if r.bottom() < bottom || (r.bottom() == bottom && self.skylines[i].w < width) {
                        bottom = r.bottom();
                        width = self.skylines[i].w;
                        index = Some(i);
                        rect = r;
                    }
                }
            }
        }

        index.map(|x| (x, rect))
    }

    fn split(&mut self, index: usize, rect: &Rect) {
        let skyline = Skyline {
            x: rect.left(),
            y: rect.bottom() + 1,
            w: rect.w,
        };

        assert!(skyline.right() <= self.border.right());
        assert!(skyline.y <= self.border.bottom());

        self.skylines.insert(index, skyline);

        let i = index + 1;
        while i < self.skylines.len() {
            assert!(self.skylines[i - 1].left() <= self.skylines[i].left());

            if self.skylines[i].left() <= self.skylines[i - 1].right() {
                let shrink = self.skylines[i - 1].right() - self.skylines[i].left() + 1;
                if self.skylines[i].w <= shrink {
                    self.skylines.remove(i);
                } else {
                    self.skylines[i].x += shrink;
                    self.skylines[i].w -= shrink;
                    break;
                }
            } else {
                break;
            }
        }
    }

    fn merge(&mut self) {
        let mut i = 1;
        while i < self.skylines.len() {
            if self.skylines[i - 1].y == self.skylines[i].y {
                self.skylines[i - 1].w += self.skylines[i].w;
                self.skylines.remove(i);
                i -= 1;
            }
            i += 1;
        }
    }
}

impl Packer for SkylinePacker {
    fn pack(&mut self, key: String, texture_rect: &Rect) -> Option<Frame> {
        let mut width = texture_rect.w;
        let mut height = texture_rect.h;

        width += self.config.texture_padding;
        height += self.config.texture_padding;

        if let Some((i, mut rect)) = self.find_skyline(width, height) {
            self.split(i, &rect);
            self.merge();

            let rotated = width != rect.w;

            rect.w -= self.config.texture_padding;
            rect.h -= self.config.texture_padding;

            Some(Frame {
                key,
                frame: rect,
                rotated,
                trimmed: false,
                source: Rect {
                    x: 0,
                    y: 0,
                    w: texture_rect.w,
                    h: texture_rect.h,
                },
            })
        } else {
            None
        }
    }

    fn can_pack(&self, texture_rect: &Rect) -> bool {
        if let Some((_, rect)) = self.find_skyline(
            texture_rect.w + self.config.texture_padding,
            texture_rect.h + self.config.texture_padding,
        ) {
            let skyline = Skyline {
                x: rect.left(),
                y: rect.bottom() + 1,
                w: rect.w,
            };

            return skyline.right() <= self.border.right() && skyline.y <= self.border.bottom();
        }
        false
    }
}
<|endoftext|>


<commit_before>//! Type represents a data type. Its implementation is pluggable.
//! So, Types are loaded from the packages.
//!

use std::mem;
use std::cmp::Ordering;
use std::rc::Rc;

use err::Result;
use rows::{MiniPage, FMiniPage};

pub type TypeFactory = Rc<Fn(&str) -> Result<Ty>>;

#[derive(Clone)]
pub struct TypeHandler {
  pub create_minipage: Rc<Fn() -> Box<MiniPage>>
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Ord)]
pub struct Ty {
  base         : String,
  comparable   : bool,
  orderable    : bool,
  handler      : TypeHandler
}

impl Ty {
	pub fn new(base: &str, comparable: bool, orderable: bool, handler: TypeHandler) -> Ty {
		Ty {
			base      : base.to_string(),
			comparable: comparable,
			orderable : orderable,
			handler   : handler
		}
	}

	pub fn base(&self) -> &str
	{
		&self.base
	}

	pub fn handler(&self) -> &TypeHandler
	{
		&self.handler
	}
}

/// For ignoring
impl Eq for TypeHandler {}

/// For ignoring
impl PartialEq for TypeHandler {
  fn eq(&self, other: &TypeHandler) -> bool {
    true
  }
}

/// For ignoring
impl PartialOrd for TypeHandler {
 fn partial_cmp(&self, other: &TypeHandler) -> Option<Ordering> {
   Some(Ordering::Equal)
 }
}

/// For ignoring
impl Ord for TypeHandler {
  fn cmp(&self, other: &TypeHandler) -> Ordering {
    Ordering::Equal
  }
}

//impl Ty {
//  pub fn kind(&self) -> &TyKind {
//    &self.kind
//  }
//
//  pub fn handler(&self) -> Rc<TypeHandler> {
//    match self.kind {
//      TyKind::I32 => {
//        let f = || -> Box<MiniPage> {Box::new(FMiniPage::new(mem::size_of::<f32>()))};
//        Rc::new(TypeHandler {create_minipage: Rc::new(f)})
//      },
//
//      TyKind::F32 => {
//        let f = || -> Box<MiniPage> {Box::new(FMiniPage::new(mem::size_of::<i32>()))};
//        Rc::new(TypeHandler {create_minipage: Rc::new(f)})
//      },
//
//      _  => { panic!("Unknown supported type") }
//    }
//  }
//}
//

/*

#[derive(Clone, PartialEq, Debug)]
pub enum Ty
{
  Bool,
  Int1,
  Int2,
  Int4,
  Int8,
  Float4,
  Float8,
  Numeric(u8, Option<u8>), // precision (1~38), scale (0 <= scale <= precision)
  Date,
  Time,
  Timez,
  Timestamp,
  Timestampz,
  Interval,
  Char(u8),                // its maximum length is 127
  Binary(u8),              // its maximum length is 127
  Clob,
  Blob,
  Array(Box<Ty>),
  Struct(Vec<Ty>),
  Map(Box<Ty>, Box<Ty>)
}

impl Ty
{
  #[allow(unused_variables)]
  pub fn size_of(&self) -> u32 {
    match *self {
      Ty::Bool                  => 1,
      Ty::Int1                  => 1,
      Ty::Int2                  => 2,
      Ty::Int4                  => 4,
      Ty::Int8                  => 8,
      Ty::Float4                => 4,
      Ty::Float8                => 8,
      Ty::Numeric(ref p, ref s) => panic!("numeric is not supported yet"),
      Ty::Date                  => 4,
      Ty::Time                  => 8,
      Ty::Timez                 => 12,
      Ty::Timestamp             => 8,
      Ty::Timestampz            => 12,
      Ty::Interval              => 12,
      Ty::Char(len)             => len as u32,
      Ty::Binary(len)           => len as u32,
      Ty::Clob                  => mem::size_of::<TEXT>() as u32,
      Ty::Blob                  => mem::size_of::<TEXT>() as u32,
      Ty::Array(ref ty)         => panic!("array is not supported yet"),
      Ty::Struct(ref tys)       => panic!("array is not supported yet"),
      Ty::Map(ref kt, ref vt)   => panic!("map is not supported yet"),
    }
  }

  #[allow(unused_variables)]
  pub fn is_variable(&self) -> bool {
    match *self {
      Ty::Char(len) | Ty::Binary(len) => true,
      _ => false
    }
  }
}

impl fmt::Display for Ty {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      Ty::Bool                    => write!(f, "bool"),
      Ty::Int1                    => write!(f, "int1"),
      Ty::Int2                    => write!(f, "int2"),
      Ty::Int4                    => write!(f, "int4"),
      Ty::Int8                    => write!(f, "int8"),
      Ty::Float4                  => write!(f, "float4"),
      Ty::Float8                  => write!(f, "float8"),
      Ty::Numeric(ref p,ref s)    => {
        match *s {
          Some(ref scale) => write!(f, "numeric ({}, {})", p, scale),
          None            => write!(f, "numeric ({})", p)
        }
      }
      Ty::Date                    => write!(f, "date"),
      Ty::Time                    => write!(f, "time"),
      Ty::Timez                   => write!(f, "time with timezone"),
      Ty::Timestamp               => write!(f, "timestamp"),
      Ty::Timestampz              => write!(f, "timeztamp with timezone"),
      Ty::Interval                => write!(f, "interval"),
      Ty::Char(ref len)           => write!(f, "char({})", len),
      Ty::Binary(ref len)         => write!(f, "binary({})", len),
      Ty::Clob                    => write!(f, "clob"),
      Ty::Blob                    => write!(f, "blob"),
      Ty::Array(ref ty)           => write!(f, "array<{}>", ty),
      Ty::Struct(ref tys)         => {
        write!(f, "struct({})", tys.iter().map(|f| format!("{}", f)).join(", "))
      },
      Ty::Map (ref kty, ref vty)  => write!(f, "map<{},{}>", kty, vty)
    }
  }
}

/// Determine a result data type from two expression data types.
#[allow(unused_variables)]
pub fn result_data_ty(lhs_ty: &Ty, rhs_ty: &Ty) -> Ty {
  match *lhs_ty {
    Ty::Bool => {
      match *rhs_ty {
        Ty::Bool => rhs_ty.clone(),
        _ => panic!("Undefined Operator")
      }
    },

    Ty::Int1 => {
      match *rhs_ty {
        Ty::Int1   |
        Ty::Int2   |
        Ty::Int4   |
        Ty::Int8   |
        Ty::Float4 |
        Ty::Float8 => rhs_ty.clone(),
        _ => panic!("Undefined Operator")
      }
    },

    Ty::Int2 => {
      match *rhs_ty {
        Ty::Int2   |
        Ty::Int4   |
        Ty::Int8   |
        Ty::Float4 |
        Ty::Float8 => rhs_ty.clone(),

        Ty::Int1   => lhs_ty.clone(),
        _ => panic!("Undefined Operator")
      }
    },

    Ty::Int4 => {
      match *rhs_ty {
        Ty::Int4   |
        Ty::Int8   |
        Ty::Float4 |
        Ty::Float8 => rhs_ty.clone(),

        Ty::Int1 |
        Ty::Int2 => lhs_ty.clone(),

        _ => panic!("Undefined Operator")
      }
    },

    Ty::Int8 => {
      match *rhs_ty {
        Ty::Int8   |
        Ty::Float4 |
        Ty::Float8 => rhs_ty.clone(),

        Ty::Int1 |
        Ty::Int2 |
        Ty::Int4 => lhs_ty.clone(),

        _ => panic!("Undefined Operator")
      }
    },

    Ty::Float4 => {
      match *rhs_ty {
        Ty::Float4 |
        Ty::Float8 => rhs_ty.clone(),

        Ty::Int1 |
        Ty::Int2 |
        Ty::Int4 |
        Ty::Int8 => lhs_ty.clone(),

        _ => panic!("Undefined Operator")
      }
    },

    Ty::Float8 => {
      match *rhs_ty {
        Ty::Float8 => rhs_ty.clone(),

        Ty::Int1   |
        Ty::Int2   |
        Ty::Int4   |
        Ty::Int8   |
        Ty::Float4 => lhs_ty.clone(),

        _ => panic!("Undefined Operator")
      }
    },

    Ty::Numeric(ref p, ref s) => {
      panic!("Undefined operator")
    },

    Ty::Date => {
      panic!("Undefined Operator")
    },

    Ty::Time => {
      panic!("Undefined Operator")
    },

    Ty::Timez => {
      panic!("Undefined Operator")
    },

    Ty::Timestamp => {
      panic!("Undefined Operator")
    },

    Ty::Timestampz => {
      panic!("Undefined Operator")
    },

    Ty::Interval => {
      panic!("Undefined Operator")
    },

    Ty::Char(ref len) => {
      panic!("Undefined Operator")
    },

    Ty::Binary(ref len) => {
      panic!("Undefined Operator")
    },

    Ty::Clob => {
      match *rhs_ty {
        Ty::Clob => rhs_ty.clone(),
        _ => panic!("Undefined Operator")
      }
    },

    Ty::Blob => {
      match *rhs_ty {
        Ty::Blob => rhs_ty.clone(),
        _ => panic!("Undefined Operator")
      }
    },

    Ty::Array(ref ty) => {
      panic!("Undefined Operator")
    }

    Ty::Struct(ref tys) => {
      panic!("Undefined Operator")
    },

    Ty::Map(ref kty, ref vty) => {
      panic!("Undefined Operator")
    }
  }
}
*/

pub const BOOL_STR      : &'static str = "bool";
pub const I32_STR       : &'static str = "i32";
pub const F32_STR       : &'static str = "i32";

pub fn bool_ty() -> Ty {
	let handler = TypeHandler {
	 	create_minipage: Rc::new(|| -> Box<MiniPage> {
			Box::new(FMiniPage::new(mem::size_of::<bool>()))
		})
  };

	Ty::new(BOOL_STR, true, true, handler)
}

pub fn i32_ty() -> Ty {
	let handler = TypeHandler {
	 	create_minipage: Rc::new(|| -> Box<MiniPage> {
			Box::new(FMiniPage::new(mem::size_of::<i32>()))
		})
  };

	Ty::new(I32_STR, true, true, handler)
}

pub fn f32_ty() -> Ty {
	let handler = TypeHandler {
	 	create_minipage: Rc::new(|| -> Box<MiniPage> {
			Box::new(FMiniPage::new(mem::size_of::<f32>()))
		})
  };

	Ty::new(F32_STR, true, true, handler)
}<commit_msg>Add more builtin type factory functions.<commit_after>//! Type represents a data type. Its implementation is pluggable.
//! So, Types are loaded from the packages.
//!

use std::mem;
use std::cmp::Ordering;
use std::rc::Rc;

use err::Result;
use rows::{MiniPage, FMiniPage};

pub type TypeFactory = Rc<Fn(&str) -> Result<Ty>>;

#[derive(Clone)]
pub struct TypeHandler {
  pub create_minipage: Rc<Fn() -> Box<MiniPage>>
}

#[derive(Clone, Eq, PartialEq, PartialOrd, Ord)]
pub struct Ty {
  base         : String,
  comparable   : bool,
  orderable    : bool,
  handler      : TypeHandler
}

impl Ty {
	pub fn new(base: &str, comparable: bool, orderable: bool, handler: TypeHandler) -> Ty {
		Ty {
			base      : base.to_string(),
			comparable: comparable,
			orderable : orderable,
			handler   : handler
		}
	}

	pub fn base(&self) -> &str
	{
		&self.base
	}

	pub fn handler(&self) -> &TypeHandler
	{
		&self.handler
	}
}

/// For ignoring
impl Eq for TypeHandler {}

/// For ignoring
impl PartialEq for TypeHandler {
  fn eq(&self, other: &TypeHandler) -> bool {
    true
  }
}

/// For ignoring
impl PartialOrd for TypeHandler {
 fn partial_cmp(&self, other: &TypeHandler) -> Option<Ordering> {
   Some(Ordering::Equal)
 }
}

/// For ignoring
impl Ord for TypeHandler {
  fn cmp(&self, other: &TypeHandler) -> Ordering {
    Ordering::Equal
  }
}

//impl Ty {
//  pub fn kind(&self) -> &TyKind {
//    &self.kind
//  }
//
//  pub fn handler(&self) -> Rc<TypeHandler> {
//    match self.kind {
//      TyKind::I32 => {
//        let f = || -> Box<MiniPage> {Box::new(FMiniPage::new(mem::size_of::<f32>()))};
//        Rc::new(TypeHandler {create_minipage: Rc::new(f)})
//      },
//
//      TyKind::F32 => {
//        let f = || -> Box<MiniPage> {Box::new(FMiniPage::new(mem::size_of::<i32>()))};
//        Rc::new(TypeHandler {create_minipage: Rc::new(f)})
//      },
//
//      _  => { panic!("Unknown supported type") }
//    }
//  }
//}
//

/*

#[derive(Clone, PartialEq, Debug)]
pub enum Ty
{
  Bool,
  Int1,
  Int2,
  Int4,
  Int8,
  Float4,
  Float8,
  Numeric(u8, Option<u8>), // precision (1~38), scale (0 <= scale <= precision)
  Date,
  Time,
  Timez,
  Timestamp,
  Timestampz,
  Interval,
  Char(u8),                // its maximum length is 127
  Binary(u8),              // its maximum length is 127
  Clob,
  Blob,
  Array(Box<Ty>),
  Struct(Vec<Ty>),
  Map(Box<Ty>, Box<Ty>)
}

impl Ty
{
  #[allow(unused_variables)]
  pub fn size_of(&self) -> u32 {
    match *self {
      Ty::Bool                  => 1,
      Ty::Int1                  => 1,
      Ty::Int2                  => 2,
      Ty::Int4                  => 4,
      Ty::Int8                  => 8,
      Ty::Float4                => 4,
      Ty::Float8                => 8,
      Ty::Numeric(ref p, ref s) => panic!("numeric is not supported yet"),
      Ty::Date                  => 4,
      Ty::Time                  => 8,
      Ty::Timez                 => 12,
      Ty::Timestamp             => 8,
      Ty::Timestampz            => 12,
      Ty::Interval              => 12,
      Ty::Char(len)             => len as u32,
      Ty::Binary(len)           => len as u32,
      Ty::Clob                  => mem::size_of::<TEXT>() as u32,
      Ty::Blob                  => mem::size_of::<TEXT>() as u32,
      Ty::Array(ref ty)         => panic!("array is not supported yet"),
      Ty::Struct(ref tys)       => panic!("array is not supported yet"),
      Ty::Map(ref kt, ref vt)   => panic!("map is not supported yet"),
    }
  }

  #[allow(unused_variables)]
  pub fn is_variable(&self) -> bool {
    match *self {
      Ty::Char(len) | Ty::Binary(len) => true,
      _ => false
    }
  }
}

impl fmt::Display for Ty {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      Ty::Bool                    => write!(f, "bool"),
      Ty::Int1                    => write!(f, "int1"),
      Ty::Int2                    => write!(f, "int2"),
      Ty::Int4                    => write!(f, "int4"),
      Ty::Int8                    => write!(f, "int8"),
      Ty::Float4                  => write!(f, "float4"),
      Ty::Float8                  => write!(f, "float8"),
      Ty::Numeric(ref p,ref s)    => {
        match *s {
          Some(ref scale) => write!(f, "numeric ({}, {})", p, scale),
          None            => write!(f, "numeric ({})", p)
        }
      }
      Ty::Date                    => write!(f, "date"),
      Ty::Time                    => write!(f, "time"),
      Ty::Timez                   => write!(f, "time with timezone"),
      Ty::Timestamp               => write!(f, "timestamp"),
      Ty::Timestampz              => write!(f, "timeztamp with timezone"),
      Ty::Interval                => write!(f, "interval"),
      Ty::Char(ref len)           => write!(f, "char({})", len),
      Ty::Binary(ref len)         => write!(f, "binary({})", len),
      Ty::Clob                    => write!(f, "clob"),
      Ty::Blob                    => write!(f, "blob"),
      Ty::Array(ref ty)           => write!(f, "array<{}>", ty),
      Ty::Struct(ref tys)         => {
        write!(f, "struct({})", tys.iter().map(|f| format!("{}", f)).join(", "))
      },
      Ty::Map (ref kty, ref vty)  => write!(f, "map<{},{}>", kty, vty)
    }
  }
}

/// Determine a result data type from two expression data types.
#[allow(unused_variables)]
pub fn result_data_ty(lhs_ty: &Ty, rhs_ty: &Ty) -> Ty {
  match *lhs_ty {
    Ty::Bool => {
      match *rhs_ty {
        Ty::Bool => rhs_ty.clone(),
        _ => panic!("Undefined Operator")
      }
    },

    Ty::Int1 => {
      match *rhs_ty {
        Ty::Int1   |
        Ty::Int2   |
        Ty::Int4   |
        Ty::Int8   |
        Ty::Float4 |
        Ty::Float8 => rhs_ty.clone(),
        _ => panic!("Undefined Operator")
      }
    },

    Ty::Int2 => {
      match *rhs_ty {
        Ty::Int2   |
        Ty::Int4   |
        Ty::Int8   |
        Ty::Float4 |
        Ty::Float8 => rhs_ty.clone(),

        Ty::Int1   => lhs_ty.clone(),
        _ => panic!("Undefined Operator")
      }
    },

    Ty::Int4 => {
      match *rhs_ty {
        Ty::Int4   |
        Ty::Int8   |
        Ty::Float4 |
        Ty::Float8 => rhs_ty.clone(),

        Ty::Int1 |
        Ty::Int2 => lhs_ty.clone(),

        _ => panic!("Undefined Operator")
      }
    },

    Ty::Int8 => {
      match *rhs_ty {
        Ty::Int8   |
        Ty::Float4 |
        Ty::Float8 => rhs_ty.clone(),

        Ty::Int1 |
        Ty::Int2 |
        Ty::Int4 => lhs_ty.clone(),

        _ => panic!("Undefined Operator")
      }
    },

    Ty::Float4 => {
      match *rhs_ty {
        Ty::Float4 |
        Ty::Float8 => rhs_ty.clone(),

        Ty::Int1 |
        Ty::Int2 |
        Ty::Int4 |
        Ty::Int8 => lhs_ty.clone(),

        _ => panic!("Undefined Operator")
      }
    },

    Ty::Float8 => {
      match *rhs_ty {
        Ty::Float8 => rhs_ty.clone(),

        Ty::Int1   |
        Ty::Int2   |
        Ty::Int4   |
        Ty::Int8   |
        Ty::Float4 => lhs_ty.clone(),

        _ => panic!("Undefined Operator")
      }
    },

    Ty::Numeric(ref p, ref s) => {
      panic!("Undefined operator")
    },

    Ty::Date => {
      panic!("Undefined Operator")
    },

    Ty::Time => {
      panic!("Undefined Operator")
    },

    Ty::Timez => {
      panic!("Undefined Operator")
    },

    Ty::Timestamp => {
      panic!("Undefined Operator")
    },

    Ty::Timestampz => {
      panic!("Undefined Operator")
    },

    Ty::Interval => {
      panic!("Undefined Operator")
    },

    Ty::Char(ref len) => {
      panic!("Undefined Operator")
    },

    Ty::Binary(ref len) => {
      panic!("Undefined Operator")
    },

    Ty::Clob => {
      match *rhs_ty {
        Ty::Clob => rhs_ty.clone(),
        _ => panic!("Undefined Operator")
      }
    },

    Ty::Blob => {
      match *rhs_ty {
        Ty::Blob => rhs_ty.clone(),
        _ => panic!("Undefined Operator")
      }
    },

    Ty::Array(ref ty) => {
      panic!("Undefined Operator")
    }

    Ty::Struct(ref tys) => {
      panic!("Undefined Operator")
    },

    Ty::Map(ref kty, ref vty) => {
      panic!("Undefined Operator")
    }
  }
}
*/

pub const BOOL_STR      : &'static str = "bool";
pub const I8_STR        : &'static str = "i32";
pub const I32_STR       : &'static str = "i32";
pub const I64_STR       : &'static str = "i32";
pub const F32_STR       : &'static str = "i32";
pub const F64_STR       : &'static str = "i32";

pub fn bool_ty() -> Ty {
	let handler = TypeHandler {
	 	create_minipage: Rc::new(|| -> Box<MiniPage> {
			Box::new(FMiniPage::new(mem::size_of::<bool>()))
		})
  };

	Ty::new(BOOL_STR, true, true, handler)
}

pub fn i8_ty() -> Ty {
	let handler = TypeHandler {
	 	create_minipage: Rc::new(|| -> Box<MiniPage> {
			Box::new(FMiniPage::new(mem::size_of::<i8>()))
		})
  };

	Ty::new(I8_STR, true, true, handler)
}

pub fn i32_ty() -> Ty {
	let handler = TypeHandler {
	 	create_minipage: Rc::new(|| -> Box<MiniPage> {
			Box::new(FMiniPage::new(mem::size_of::<i32>()))
		})
  };

	Ty::new(I32_STR, true, true, handler)
}

pub fn i64_ty() -> Ty {
	let handler = TypeHandler {
	 	create_minipage: Rc::new(|| -> Box<MiniPage> {
			Box::new(FMiniPage::new(mem::size_of::<i64>()))
		})
  };

	Ty::new(I64_STR, true, true, handler)
}

pub fn f32_ty() -> Ty {
	let handler = TypeHandler {
	 	create_minipage: Rc::new(|| -> Box<MiniPage> {
			Box::new(FMiniPage::new(mem::size_of::<f32>()))
		})
  };

	Ty::new(F32_STR, true, true, handler)
}

pub fn f64_ty() -> Ty {
	let handler = TypeHandler {
	 	create_minipage: Rc::new(|| -> Box<MiniPage> {
			Box::new(FMiniPage::new(mem::size_of::<f64>()))
		})
  };

	Ty::new(F64_STR, true, true, handler)
}<|endoftext|>