1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use bitflags::bitflags;
use serde::{
    de::{Deserialize, Deserializer},
    ser::{Serialize, Serializer},
};

bitflags! {
    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
    pub struct UserFlags: u64 {
        /// Discord Employee.
        const STAFF = 1;
        /// Partnered server owner.
        const PARTNER = 1 << 1;
        /// HypeSquad events member.
        const HYPESQUAD = 1 << 2;
        /// Bug hunter level 1.
        const BUG_HUNTER_LEVEL_1 = 1 << 3;
        /// House Bravery member.
        const HYPESQUAD_ONLINE_HOUSE_1 = 1 << 6;
        /// House Brilliance member.
        const HYPESQUAD_ONLINE_HOUSE_2 = 1 << 7;
        /// House Balance member.
        const HYPESQUAD_ONLINE_HOUSE_3 = 1 << 8;
        /// Early Nitro supporter.
        const PREMIUM_EARLY_SUPPORTER = 1 << 9;
        /// User is in a team.
        const TEAM_PSEUDO_USER = 1 << 10;
        /// Bug hunter level 2.
        const BUG_HUNTER_LEVEL_2 = 1 << 14;
        /// Verified bot.
        const VERIFIED_BOT = 1 << 16;
        /// Early verified bot developer.
        const VERIFIED_DEVELOPER = 1 << 17;
        /// Moderator Programs Alumni
        const MODERATOR_PROGRAMS_ALUMNI = 1 << 18;
        /// Bot uses only HTTP interactions and is shown in the online member
        /// list.
        const BOT_HTTP_INTERACTIONS = 1 << 19;
        /// User is an [Active Developer].
        ///
        /// [Active Developer]: https://support-dev.discord.com/hc/articles/10113997751447
        const ACTIVE_DEVELOPER = 1 << 22;
    }
}

impl<'de> Deserialize<'de> for UserFlags {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        Ok(Self::from_bits_truncate(u64::deserialize(deserializer)?))
    }
}

impl Serialize for UserFlags {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_u64(self.bits())
    }
}

#[cfg(test)]
mod tests {
    #![allow(deprecated)]

    use super::UserFlags;
    use serde::{Deserialize, Serialize};
    use serde_test::Token;
    use static_assertions::{assert_impl_all, const_assert_eq};
    use std::{
        fmt::{Binary, Debug, LowerHex, Octal, UpperHex},
        hash::Hash,
        ops::{
            BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not, Sub, SubAssign,
        },
    };

    assert_impl_all!(
        UserFlags: Binary,
        BitAnd,
        BitAndAssign,
        BitOr,
        BitOrAssign,
        BitXor,
        BitXorAssign,
        Clone,
        Copy,
        Debug,
        Deserialize<'static>,
        Eq,
        Extend<UserFlags>,
        FromIterator<UserFlags>,
        Hash,
        LowerHex,
        Not,
        Octal,
        PartialEq,
        Send,
        Serialize,
        Sub,
        SubAssign,
        Sync,
        UpperHex
    );

    const_assert_eq!(UserFlags::STAFF.bits(), 1);
    const_assert_eq!(UserFlags::PARTNER.bits(), 1 << 1);
    const_assert_eq!(UserFlags::HYPESQUAD.bits(), 1 << 2);
    const_assert_eq!(UserFlags::BUG_HUNTER_LEVEL_1.bits(), 1 << 3);
    const_assert_eq!(UserFlags::HYPESQUAD_ONLINE_HOUSE_1.bits(), 1 << 6);
    const_assert_eq!(UserFlags::HYPESQUAD_ONLINE_HOUSE_2.bits(), 1 << 7);
    const_assert_eq!(UserFlags::HYPESQUAD_ONLINE_HOUSE_3.bits(), 1 << 8);
    const_assert_eq!(UserFlags::PREMIUM_EARLY_SUPPORTER.bits(), 1 << 9);
    const_assert_eq!(UserFlags::TEAM_PSEUDO_USER.bits(), 1 << 10);
    const_assert_eq!(UserFlags::BUG_HUNTER_LEVEL_2.bits(), 1 << 14);
    const_assert_eq!(UserFlags::VERIFIED_BOT.bits(), 1 << 16);
    const_assert_eq!(UserFlags::VERIFIED_DEVELOPER.bits(), 1 << 17);
    const_assert_eq!(UserFlags::MODERATOR_PROGRAMS_ALUMNI.bits(), 1 << 18);
    const_assert_eq!(UserFlags::BOT_HTTP_INTERACTIONS.bits(), 1 << 19);
    const_assert_eq!(UserFlags::ACTIVE_DEVELOPER.bits(), 1 << 22);

    #[test]
    fn serde() {
        serde_test::assert_tokens(
            &UserFlags::PARTNER,
            &[Token::U64(UserFlags::PARTNER.bits())],
        );
        // Deserialization truncates unknown bits.
        serde_test::assert_de_tokens(&UserFlags::empty(), &[Token::U64(1 << 63)]);
    }
}