use serde::{Deserialize, Serialize};
use std::fmt::Debug;
#[derive(Copy, Clone, Eq, PartialEq, Serialize, Deserialize, Debug)]
#[repr(u16)]
#[cfg_attr(feature = "graphql", derive(async_graphql::Enum))]
#[cfg_attr(feature = "graphql", graphql(name = "UserPermission"))]
pub enum Permission {
ManageApps,
ManageDomains,
ManageUsers,
ManageGroups,
ManageProxies,
ManageIssuers,
ConfigureNetwork,
ManageSysComponents,
ManageHardware,
Escalate,
VendorReserved, ManageAppStores,
ManageAppStorage,
InstallRootApps,
AddTrustedDomains,
}
#[derive(Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub struct PermissionSet(u16);
impl Debug for PermissionSet {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut first = true;
write!(f, "[")?;
for perm in self.into_iter() {
if first {
first = false;
} else {
write!(f, ", ")?;
}
write!(f, "{perm:?}")?;
}
write!(f, "]")
}
}
#[inline]
const fn perm_to_uint(value: Permission) -> u16 {
match value {
Permission::ManageApps => 0b0000000000000001,
Permission::ManageDomains => 0b0000000000000010,
Permission::ManageUsers => 0b0000000000000100,
Permission::ManageGroups => 0b0000000000001000,
Permission::ManageProxies => 0b0000000000010000,
Permission::ManageIssuers => 0b0000000000100000,
Permission::ConfigureNetwork => 0b0000000001000000,
Permission::ManageSysComponents => 0b0000000010000000,
Permission::ManageHardware => 0b0000000100000000,
Permission::Escalate => 0b0000001000000000,
Permission::VendorReserved => 0b0000010000000000,
Permission::ManageAppStores => 0b0000100000000000,
Permission::ManageAppStorage => 0b0001000000000000,
Permission::InstallRootApps => 0b0010000000000000,
Permission::AddTrustedDomains => 0b0100000000000000,
}
}
impl PermissionSet {
pub fn add(&mut self, perm: Permission) {
self.0 |= perm_to_uint(perm);
}
pub fn remove(&mut self, perm: Permission) {
self.0 &= !perm_to_uint(perm);
}
pub fn has(&self, perm: Permission) -> bool {
self.0 & perm_to_uint(perm) != 0
}
pub const fn empty() -> Self {
PermissionSet(0)
}
pub const fn from_perms_static(perms: &'static [Permission]) -> Self {
let mut set: u16 = 0;
let mut i = 0;
while i < perms.len() {
set |= perm_to_uint(perms[i]);
i += 1;
}
PermissionSet(set)
}
pub const fn full() -> Self {
PermissionSet(0b0111111111111111)
}
}
impl From<&[Permission]> for PermissionSet {
fn from(permissions: &[Permission]) -> Self {
let mut set = PermissionSet(0);
for perm in permissions {
set.add(*perm);
}
set
}
}
impl From<PermissionSet> for u16 {
fn from(set: PermissionSet) -> u16 {
set.0
}
}
impl From<u16> for PermissionSet {
fn from(value: u16) -> Self {
PermissionSet(value)
}
}
pub struct PermissionSetIter {
value: u16,
current: u16,
}
impl Iterator for PermissionSetIter {
type Item = Permission;
fn next(&mut self) -> Option<Self::Item> {
while self.current != 0 {
let bit = self.current.trailing_zeros();
self.current &= !(1 << bit);
if self.value & (1 << bit) != 0 {
return Some(match bit {
0 => Permission::ManageApps,
1 => Permission::ManageDomains,
2 => Permission::ManageUsers,
3 => Permission::ManageGroups,
4 => Permission::ManageProxies,
5 => Permission::ManageIssuers,
6 => Permission::ConfigureNetwork,
7 => Permission::ManageSysComponents,
8 => Permission::ManageHardware,
9 => Permission::Escalate,
10 => Permission::VendorReserved,
11 => Permission::ManageAppStores,
12 => Permission::ManageAppStorage,
13 => Permission::InstallRootApps,
14 => Permission::AddTrustedDomains,
_ => return None,
});
}
}
None
}
}
impl IntoIterator for PermissionSet {
type Item = Permission;
type IntoIter = PermissionSetIter;
fn into_iter(self) -> Self::IntoIter {
PermissionSetIter {
value: self.0,
current: self.0,
}
}
}
#[cfg(test)]
mod test {
use super::{Permission, PermissionSet};
#[test]
fn test_permission_set() {
let mut set = PermissionSet(0);
assert!(!set.has(Permission::ManageApps));
set.add(Permission::ManageApps);
assert!(set.has(Permission::ManageApps));
set.add(Permission::ManageGroups);
assert!(set.has(Permission::ManageApps));
assert!(set.has(Permission::ManageGroups));
set.remove(Permission::ManageApps);
assert!(!set.has(Permission::ManageApps));
assert!(set.has(Permission::ManageGroups));
}
#[test]
fn test_permission_set_iter() {
let mut set = PermissionSet(0);
set.add(Permission::ManageApps);
set.add(Permission::ManageGroups);
let mut iter = set.into_iter();
assert_eq!(iter.next(), Some(Permission::ManageApps));
assert_eq!(iter.next(), Some(Permission::ManageGroups));
assert_eq!(iter.next(), None);
}
#[test]
fn test_format_permission_set() {
let mut set = PermissionSet(0);
set.add(Permission::ManageApps);
set.add(Permission::ManageGroups);
assert_eq!(format!("{set:?}"), "[ManageApps, ManageGroups]");
}
#[test]
fn test_format_permission_set_fixed_order() {
let mut set = PermissionSet(0);
set.add(Permission::ManageGroups);
set.add(Permission::ManageApps);
assert_eq!(format!("{set:?}"), "[ManageApps, ManageGroups]");
}
}