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
mod channel;
mod server;
mod user;

pub use channel::*;
use revolt_result::{create_error, Result};
pub use server::*;
pub use user::*;

/// Holds a permission value to manipulate.
#[derive(Clone, Debug)]
pub struct PermissionValue(u64);

impl PermissionValue {
    /// Apply a given override to this value
    pub fn apply(&mut self, v: Override) {
        self.allow(v.allow);
        self.revoke(v.deny);
    }

    /// Allow given permissions
    pub fn allow(&mut self, v: u64) {
        self.0 |= v;
    }

    /// Revoke given permissions
    pub fn revoke(&mut self, v: u64) {
        self.0 &= !v;
    }

    /// Revoke all permissions
    pub fn revoke_all(&mut self) {
        self.0 = 0;
    }

    /// Restrict to given permissions
    pub fn restrict(&mut self, v: u64) {
        self.0 &= v;
    }

    /// Check whether certain a permission has been granted
    pub fn has(&self, v: u64) -> bool {
        (self.0 & v) == v
    }

    /// Check whether certain a user permission has been granted
    pub fn has_user_permission(&self, permission: UserPermission) -> bool {
        self.has(permission as u64)
    }

    /// Check whether certain a channel permission has been granted
    pub fn has_channel_permission(&self, permission: ChannelPermission) -> bool {
        self.has(permission as u64)
    }

    /// Throw if missing user permission
    pub fn throw_if_lacking_user_permission(&self, permission: UserPermission) -> Result<()> {
        if self.has_user_permission(permission) {
            Ok(())
        } else {
            Err(create_error!(MissingPermission {
                permission: permission.to_string()
            }))
        }
    }

    /// Throw if missing channel permission
    pub fn throw_if_lacking_channel_permission(&self, permission: ChannelPermission) -> Result<()> {
        if self.has_channel_permission(permission) {
            Ok(())
        } else {
            Err(create_error!(MissingPermission {
                permission: permission.to_string()
            }))
        }
    }

    /// Throw an error if we cannot grant permissions on either allows or denies
    /// going from the previous given value to the next given value.
    ///
    /// We need to check any:
    /// - allows added (permissions now granted)
    /// - denies removed (permissions now neutral or granted)
    pub async fn throw_permission_override<C>(
        &self,
        current_value: C,
        next_value: &Override,
    ) -> Result<()>
    where
        C: Into<Option<Override>>,
    {
        let current_value = current_value.into();

        if let Some(current_value) = current_value {
            if !self.has(!current_value.allows() & next_value.allows())
                || !self.has(current_value.denies() & !next_value.denies())
            {
                return Err(create_error!(CannotGiveMissingPermissions));
            }
        } else if !self.has(next_value.allows()) {
            return Err(create_error!(CannotGiveMissingPermissions));
        }

        Ok(())
    }
}

impl From<i64> for PermissionValue {
    fn from(v: i64) -> Self {
        Self(v as u64)
    }
}

impl From<u64> for PermissionValue {
    fn from(v: u64) -> Self {
        Self(v)
    }
}

impl From<PermissionValue> for u64 {
    fn from(v: PermissionValue) -> Self {
        v.0
    }
}

impl From<ChannelPermission> for PermissionValue {
    fn from(v: ChannelPermission) -> Self {
        (v as u64).into()
    }
}