use std::fmt;
use std::ops;
use std::string::ToString;
use lazy_static::lazy_static;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Permission(u32);
impl Permission {
pub const NONE: Permission = Permission(0b00000);
pub const READ: Permission = Permission(0b00001);
pub const WRITE: Permission = Permission(0b00010);
pub const CREATE: Permission = Permission(0b00100);
pub const DELETE: Permission = Permission(0b01000);
pub const ADMIN: Permission = Permission(0b10000);
pub const ALL: Permission = Permission(0b11111);
pub(crate) fn from_raw(bits: u32) -> Permission {
Permission(bits)
}
pub(crate) fn code(&self) -> u32 {
self.0
}
pub fn can(self, permissions: Permission) -> bool {
(self & permissions) == permissions
}
}
impl ops::BitAnd for Permission {
type Output = Self;
fn bitand(self, rhs: Self) -> Self {
Permission::from_raw(self.0 & rhs.0)
}
}
impl ops::BitOr for Permission {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
Permission::from_raw(self.0 | rhs.0)
}
}
impl fmt::Display for Permission {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if *self == Permission::ALL {
write!(f, "ALL")
} else if *self == Permission::NONE {
write!(f, "NONE")
} else {
let mut first = true;
let mut tick = || {
if first {
first = false;
""
} else {
"|"
}
};
if self.can(Permission::READ) {
write!(f, "{}READ", tick())?;
}
if self.can(Permission::WRITE) {
write!(f, "{}WRITE", tick())?;
}
if self.can(Permission::CREATE) {
write!(f, "{}CREATE", tick())?;
}
if self.can(Permission::DELETE) {
write!(f, "{}DELETE", tick())?;
}
if self.can(Permission::ADMIN) {
write!(f, "{}ADMIN", tick())?;
}
Ok(())
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn permission_bitor() {
let all = Permission::READ
| Permission::WRITE
| Permission::CREATE
| Permission::DELETE
| Permission::ADMIN;
assert_eq!(Permission::ALL, all);
}
#[test]
fn permission_can() {
assert!(Permission::ALL.can(Permission::WRITE));
assert!(!Permission::WRITE.can(Permission::READ));
}
#[test]
fn permission_format() {
assert_eq!("ALL", Permission::ALL.to_string());
assert_eq!("NONE", Permission::NONE.to_string());
assert_eq!(
"READ|WRITE",
(Permission::READ | Permission::WRITE).to_string()
);
assert_eq!(
"CREATE|DELETE",
(Permission::CREATE | Permission::DELETE).to_string()
);
assert_eq!("ADMIN", Permission::ADMIN.to_string());
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Acl {
pub perms: Permission,
pub scheme: String,
pub id: String,
}
impl Acl {
pub fn new<T, U>(permissions: Permission, scheme: T, id: U) -> Acl
where
T: ToString,
U: ToString,
{
Acl {
perms: permissions,
scheme: scheme.to_string(),
id: id.to_string(),
}
}
pub fn creator_all() -> &'static Vec<Acl> {
&ACL_CREATOR_ALL
}
pub fn open_unsafe() -> &'static Vec<Acl> {
&ACL_OPEN_UNSAFE
}
pub fn read_unsafe() -> &'static Vec<Acl> {
&ACL_READ_UNSAFE
}
}
lazy_static! {
static ref ACL_CREATOR_ALL: Vec<Acl> = vec![Acl::new(Permission::ALL, "auth", "")];
static ref ACL_OPEN_UNSAFE: Vec<Acl> = vec![Acl::new(Permission::ALL, "world", "anyone")];
static ref ACL_READ_UNSAFE: Vec<Acl> = vec![Acl::new(Permission::READ, "world", "anyone")];
}
impl fmt::Display for Acl {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}:{}, {})", self.scheme, self.id, self.perms)
}
}