use super::{AtomicPermission, PermissionSet};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct PermissionMapping {
namespace: String,
entries: Vec<(u32, String)>,
}
impl PermissionMapping {
pub fn new(namespace: impl Into<String>) -> Self {
Self {
namespace: namespace.into(),
entries: Vec::new(),
}
}
pub fn add(mut self, bit: u32, action: impl Into<String>) -> Self {
self.entries.push((bit, action.into()));
self
}
pub fn namespace(&self) -> &str {
&self.namespace
}
pub fn entries(&self) -> &[(u32, String)] {
&self.entries
}
pub fn to_permission_set(&self, bits: u32) -> PermissionSet {
let mut set = PermissionSet::new();
for (mask, action) in &self.entries {
if bits & mask == *mask {
set.insert(AtomicPermission::new(&self.namespace, action));
}
}
set
}
pub fn from_permission_set(&self, set: &PermissionSet) -> u32 {
let mut bits = 0u32;
for perm in set.iter() {
if perm.namespace() == self.namespace {
for (mask, action) in &self.entries {
if perm.action() == action {
bits |= mask;
break;
}
}
}
}
bits
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn basic_roundtrip() {
let m = PermissionMapping::new("test")
.add(0x01, "read")
.add(0x02, "write")
.add(0x04, "execute");
let set = m.to_permission_set(0x05);
assert!(set.contains(&AtomicPermission::new("test", "read")));
assert!(!set.contains(&AtomicPermission::new("test", "write")));
assert!(set.contains(&AtomicPermission::new("test", "execute")));
assert_eq!(m.from_permission_set(&set), 0x05);
}
#[test]
fn empty_bits() {
let m = PermissionMapping::new("test").add(0x01, "read");
let set = m.to_permission_set(0);
assert!(set.is_empty());
assert_eq!(m.from_permission_set(&set), 0);
}
#[test]
fn ignores_other_namespace() {
let m = PermissionMapping::new("test").add(0x01, "read");
let mut set = PermissionSet::new();
set.insert(AtomicPermission::new("other", "read"));
assert_eq!(m.from_permission_set(&set), 0);
}
}