refluxer 0.2.0

Rust API wrapper for Fluxer
Documentation
use serde::{Deserialize, Deserializer, Serialize, Serializer};

bitflags::bitflags! {
    /// Permission bitfield compatible with Fluxer API.
    ///
    /// Permissions are transmitted as stringified integers over the wire
    /// (e.g. `"2048"`). This type handles the conversion transparently.
    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
    pub struct Permissions: u64 {
        const CREATE_INSTANT_INVITE = 1 << 0;
        const KICK_MEMBERS          = 1 << 1;
        const BAN_MEMBERS           = 1 << 2;
        const ADMINISTRATOR         = 1 << 3;
        const MANAGE_CHANNELS       = 1 << 4;
        const MANAGE_GUILD          = 1 << 5;
        const ADD_REACTIONS         = 1 << 6;
        const VIEW_AUDIT_LOG        = 1 << 7;
        const PRIORITY_SPEAKER      = 1 << 8;
        const STREAM                = 1 << 9;
        const VIEW_CHANNEL          = 1 << 10;
        const SEND_MESSAGES         = 1 << 11;
        const SEND_TTS_MESSAGES     = 1 << 12;
        const MANAGE_MESSAGES       = 1 << 13;
        const EMBED_LINKS           = 1 << 14;
        const ATTACH_FILES          = 1 << 15;
        const READ_MESSAGE_HISTORY  = 1 << 16;
        const MENTION_EVERYONE      = 1 << 17;
        const USE_EXTERNAL_EMOJIS   = 1 << 18;
        const CONNECT               = 1 << 20;
        const SPEAK                 = 1 << 21;
        const MUTE_MEMBERS          = 1 << 22;
        const DEAFEN_MEMBERS        = 1 << 23;
        const MOVE_MEMBERS          = 1 << 24;
        const USE_VAD               = 1 << 25;
        const CHANGE_NICKNAME       = 1 << 26;
        const MANAGE_NICKNAMES      = 1 << 27;
        const MANAGE_ROLES          = 1 << 28;
        const MANAGE_WEBHOOKS       = 1 << 29;
        const MANAGE_EMOJIS         = 1 << 30;
    }
}

impl Permissions {
    /// Check if these permissions include a specific permission.
    pub fn has(self, perm: Permissions) -> bool {
        self.contains(perm)
    }

    /// Administrators implicitly have all permissions.
    pub fn is_admin(self) -> bool {
        self.contains(Self::ADMINISTRATOR)
    }
}

impl Default for Permissions {
    fn default() -> Self {
        Self::empty()
    }
}

impl std::fmt::Display for Permissions {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.bits())
    }
}

impl From<u64> for Permissions {
    fn from(bits: u64) -> Self {
        Self::from_bits_truncate(bits)
    }
}

/// Fluxer sends permissions as stringified integers: `"2048"`.
impl Serialize for Permissions {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        serializer.serialize_str(&self.bits().to_string())
    }
}

impl<'de> Deserialize<'de> for Permissions {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        struct PermVisitor;

        impl serde::de::Visitor<'_> for PermVisitor {
            type Value = Permissions;

            fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                f.write_str("a permission integer or string")
            }

            fn visit_u64<E: serde::de::Error>(self, v: u64) -> Result<Permissions, E> {
                Ok(Permissions::from_bits_truncate(v))
            }

            fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Permissions, E> {
                let bits: u64 = v.parse().map_err(E::custom)?;
                Ok(Permissions::from_bits_truncate(bits))
            }
        }

        deserializer.deserialize_any(PermVisitor)
    }
}

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

    #[test]
    fn basic_flags() {
        let p = Permissions::SEND_MESSAGES | Permissions::VIEW_CHANNEL;
        assert!(p.has(Permissions::SEND_MESSAGES));
        assert!(p.has(Permissions::VIEW_CHANNEL));
        assert!(!p.has(Permissions::ADMINISTRATOR));
    }

    #[test]
    fn admin_check() {
        let p = Permissions::ADMINISTRATOR;
        assert!(p.is_admin());
    }

    #[test]
    fn serde_string_roundtrip() {
        let p = Permissions::SEND_MESSAGES | Permissions::VIEW_CHANNEL;
        let json = serde_json::to_string(&p).unwrap();
        assert_eq!(json, "\"3072\""); // 1024 + 2048
        let parsed: Permissions = serde_json::from_str(&json).unwrap();
        assert_eq!(p, parsed);
    }

    #[test]
    fn serde_from_number() {
        let parsed: Permissions = serde_json::from_str("3072").unwrap();
        assert!(parsed.has(Permissions::VIEW_CHANNEL));
        assert!(parsed.has(Permissions::SEND_MESSAGES));
    }

    #[test]
    fn display() {
        let p = Permissions::ADMINISTRATOR;
        assert_eq!(p.to_string(), "8");
    }
}