1use compact_str::CompactString;
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
5pub struct Permission(i32);
6
7#[rustfmt::skip]
8impl Permission {
9 pub const READ: Permission = Permission(1);
11
12 pub const WRITE: Permission = Permission(2);
14
15 pub const CREATE: Permission = Permission(4);
17
18 pub const DELETE: Permission = Permission(8);
20
21 pub const ADMIN: Permission = Permission(16);
23
24 pub const ALL: Permission = Permission(31);
26
27 pub const NONE: Permission = Permission(0);
29
30 pub(crate) fn into_raw(self) -> i32 {
31 self.0
32 }
33
34 pub(crate) fn from_raw(raw: i32) -> Permission {
35 Permission(raw)
36 }
37
38 pub fn has(self, perm: Permission) -> bool {
40 (self.0 & perm.0) == perm.0
41 }
42}
43
44impl std::ops::BitAnd for Permission {
45 type Output = Self;
46
47 fn bitand(self, rhs: Self) -> Self::Output {
49 Permission(self.0 & rhs.0)
50 }
51}
52
53impl std::ops::BitOr for Permission {
54 type Output = Self;
55
56 fn bitor(self, rhs: Self) -> Self::Output {
58 Permission(self.0 | rhs.0)
59 }
60}
61
62impl std::fmt::Display for Permission {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 if *self == Permission::ALL {
65 return f.write_str("ALL");
66 } else if *self == Permission::NONE {
67 return f.write_str("NONE");
68 }
69 [
70 (Permission::READ, "READ"),
71 (Permission::WRITE, "WRITE"),
72 (Permission::CREATE, "CREATE"),
73 (Permission::DELETE, "DELETE"),
74 (Permission::ADMIN, "ADMIN"),
75 ]
76 .into_iter()
77 .filter_map(|(perm, str)| if self.has(perm) { Some(str) } else { None })
78 .enumerate()
79 .try_for_each(|(i, str)| if i == 0 { f.write_str(str) } else { write!(f, "|{str}") })
80 }
81}
82
83#[derive(Clone, Debug, PartialEq, Eq)]
85pub struct Acl {
86 permission: Permission,
87 auth_id: AuthId,
88}
89
90#[derive(Clone, Debug, PartialEq, Eq)]
92pub struct AuthId {
93 scheme: CompactString,
94 id: CompactString,
95}
96
97impl AuthId {
98 pub fn new(scheme: &str, id: &str) -> AuthId {
100 AuthId { scheme: CompactString::new(scheme), id: CompactString::new(id) }
101 }
102
103 pub const fn new_const(scheme: &'static str, id: &'static str) -> AuthId {
105 AuthId { scheme: CompactString::new_inline(scheme), id: CompactString::new_inline(id) }
106 }
107
108 pub fn scheme(&self) -> &str {
110 self.scheme.as_str()
111 }
112
113 pub fn id(&self) -> &str {
115 self.id.as_str()
116 }
117
118 pub const fn anyone() -> AuthId {
120 Self::new_const("world", "anyone")
121 }
122
123 pub const fn authed() -> AuthId {
125 Self::new_const("auth", "")
126 }
127}
128
129#[derive(Clone, Debug, PartialEq, Eq)]
131pub struct AuthUser {
132 scheme: CompactString,
133 user: CompactString,
134}
135
136impl AuthUser {
137 pub fn new(scheme: &str, user: &str) -> AuthUser {
139 AuthUser { scheme: CompactString::new(scheme), user: CompactString::new(user) }
140 }
141
142 pub fn scheme(&self) -> &str {
144 self.scheme.as_str()
145 }
146
147 pub fn user(&self) -> &str {
149 self.user.as_str()
150 }
151}
152
153static ANYONE_ALL: [Acl; 1] = [Acl::new_const(Permission::ALL, "world", "anyone")];
154static ANYONE_READ: [Acl; 1] = [Acl::new_const(Permission::READ, "world", "anyone")];
155static CREATOR_ALL: [Acl; 1] = [Acl::new_const(Permission::ALL, "auth", "")];
156
157impl Acl {
158 pub fn new(permission: Permission, auth_id: AuthId) -> Acl {
160 Acl { permission, auth_id }
161 }
162
163 pub const fn new_const(permission: Permission, scheme: &'static str, id: &'static str) -> Acl {
165 Acl {
166 permission,
167 auth_id: AuthId { scheme: CompactString::new_inline(scheme), id: CompactString::new_inline(id) },
168 }
169 }
170
171 pub fn permission(&self) -> Permission {
173 self.permission
174 }
175
176 pub fn auth_id(&self) -> &AuthId {
178 &self.auth_id
179 }
180
181 pub fn scheme(&self) -> &str {
183 self.auth_id.scheme.as_str()
184 }
185
186 pub fn id(&self) -> &str {
188 self.auth_id.id.as_str()
189 }
190}
191
192#[derive(Clone, Copy, Debug, PartialEq, Eq)]
193enum AclsInner<'a> {
194 AnyoneAll,
195 AnyoneRead,
196 CreatorAll,
197 Acls { acls: &'a [Acl] },
198}
199
200#[derive(Clone, Copy, Debug, PartialEq, Eq)]
202pub struct Acls<'a> {
203 inner: AclsInner<'a>,
204}
205
206impl<'a> Acls<'a> {
207 pub fn new(acls: &'a [Acl]) -> Self {
209 Self { inner: AclsInner::Acls { acls } }
210 }
211
212 pub const fn anyone_all() -> Acls<'static> {
215 Acls { inner: AclsInner::AnyoneAll }
216 }
217
218 pub const fn anyone_read() -> Acls<'static> {
220 Acls { inner: AclsInner::AnyoneRead }
221 }
222
223 pub const fn creator_all() -> Acls<'static> {
226 Acls { inner: AclsInner::CreatorAll }
227 }
228}
229
230impl<'a> std::ops::Deref for Acls<'a> {
231 type Target = [Acl];
232
233 fn deref(&self) -> &'a [Acl] {
234 match self.inner {
235 AclsInner::AnyoneAll => &ANYONE_ALL,
236 AclsInner::AnyoneRead => &ANYONE_READ,
237 AclsInner::CreatorAll => &CREATOR_ALL,
238 AclsInner::Acls { acls } => acls,
239 }
240 }
241}
242
243impl<'a> From<&'a [Acl]> for Acls<'a> {
244 fn from(acls: &'a [Acl]) -> Self {
245 Self::new(acls)
246 }
247}
248
249#[cfg(test)]
250mod tests {
251 use pretty_assertions::assert_eq;
252
253 use super::*;
254
255 #[test]
256 fn permission_test() {
257 let all = Permission::READ | Permission::WRITE | Permission::CREATE | Permission::DELETE | Permission::ADMIN;
258
259 assert!(Permission::ALL.has(all));
260 assert_eq!(Permission::ALL & Permission::ALL, Permission::ALL);
261
262 assert_eq!(Permission::ALL & Permission::READ, Permission::READ);
263 assert_eq!(Permission::READ & Permission::READ, Permission::READ);
264 assert_eq!(Permission::CREATE & Permission::READ, Permission::NONE);
265 }
266
267 #[test]
268 fn permission_display() {
269 assert_eq!(Permission::ALL.to_string(), "ALL");
270 assert_eq!(Permission::ADMIN.to_string(), "ADMIN");
271
272 let perms = Permission::READ | Permission::WRITE | Permission::CREATE | Permission::DELETE;
273 assert_eq!(perms.to_string(), "READ|WRITE|CREATE|DELETE");
274 }
275
276 #[test]
277 fn test_acls() {
278 assert_eq!(&Acls::anyone_all() as &[Acl], &ANYONE_ALL);
279 assert_eq!(&Acls::anyone_read() as &[Acl], &ANYONE_READ);
280 assert_eq!(&Acls::creator_all() as &[Acl], &CREATOR_ALL);
281 assert_eq!(&Acls::new(&CREATOR_ALL) as &[Acl], &CREATOR_ALL);
282 }
283}