use core::fmt;
use once_cell::sync::Lazy;
pub static FSACTION_VALUES: Lazy<Vec<FsAction>> = Lazy::new(FsAction::values);
#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum FsAction {
None,
Execute,
Write,
WriteExecute,
Read,
ReadExecute,
ReadWrite,
All,
}
impl FsAction {
fn values() -> Vec<Self> {
vec![
Self::None,
Self::Execute,
Self::Write,
Self::WriteExecute,
Self::Read,
Self::ReadExecute,
Self::ReadWrite,
Self::All,
]
}
pub fn ordinal(&self) -> usize {
*self as usize
}
pub fn symbol(&self) -> String {
self.to_string()
}
pub fn implies(&self, that: Option<&FsAction>) -> bool {
match that {
Some(that) => self.ordinal() & that.ordinal() == that.ordinal(),
None => false,
}
}
pub fn and(&self, that: &FsAction) -> FsAction {
FSACTION_VALUES[self.ordinal() & that.ordinal()]
}
pub fn or(&self, that: &FsAction) -> FsAction {
FSACTION_VALUES[self.ordinal() | that.ordinal()]
}
pub fn not(&self) -> FsAction {
FSACTION_VALUES[7 - self.ordinal()]
}
pub fn get_fs_action(permission: &str) -> Option<FsAction> {
FSACTION_VALUES
.iter()
.filter(|a| a.symbol() == permission)
.next()
.cloned()
}
}
impl fmt::Display for FsAction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::None => write!(f, "---"),
Self::Execute => write!(f, "--x"),
Self::Write => write!(f, "-w-"),
Self::WriteExecute => write!(f, "-wx"),
Self::Read => write!(f, "r--"),
Self::ReadExecute => write!(f, "r-x"),
Self::ReadWrite => write!(f, "rw-"),
Self::All => write!(f, "rwx"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fs_action() {
FsAction::values()
.iter()
.for_each(|a| assert!(FsAction::All.implies(Some(a))));
FsAction::values().iter().for_each(|a| {
assert!(if *a == FsAction::None {
FsAction::None.implies(Some(a))
} else {
!FsAction::None.implies(Some(a))
});
});
FsAction::values().iter().for_each(|a| {
assert!(if *a == FsAction::ReadExecute
|| *a == FsAction::Read
|| *a == FsAction::Execute
|| *a == FsAction::None
{
FsAction::ReadExecute.implies(Some(a))
} else {
!FsAction::ReadExecute.implies(Some(a))
});
});
assert!(FsAction::Execute == FsAction::Execute.and(&FsAction::ReadExecute));
assert!(FsAction::Read == FsAction::Read.and(&FsAction::ReadExecute));
assert!(FsAction::None == FsAction::Write.and(&FsAction::ReadExecute));
assert!(FsAction::Read == FsAction::ReadExecute.and(&FsAction::ReadWrite));
assert!(FsAction::None == FsAction::ReadExecute.and(&FsAction::Write));
assert!(FsAction::WriteExecute == FsAction::All.and(&FsAction::WriteExecute));
}
}