use core::fmt::Display;
use bitflags::bitflags;
use crate::types::Mode;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Class {
Owner,
Group,
Other,
}
#[derive(Debug, Clone, Copy)]
pub struct Triad {
pub read: bool,
pub write: bool,
pub execution: bool,
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Permissions: u16 {
const OTHER_EXECUTION = 0o000_001;
const OTHER_WRITE = 0o000_002;
const OTHER_READ = 0o000_004;
const GROUP_EXECUTION = 0o000_010;
const GROUP_WRITE = 0o000_020;
const GROUP_READ = 0o000_040;
const USER_EXECUTION = 0o000_100;
const USER_WRITE = 0o000_200;
const USER_READ = 0o000_400;
const STICKY = 0o001_000;
const SET_GROUP_ID = 0o002_000;
const SET_USER_ID = 0o004_000;
}
}
impl Display for Permissions {
fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
fmt,
"{}{}{}{}{}{}{}{}{}",
if self.contains(Self::USER_READ) { "r" } else { "-" },
if self.contains(Self::USER_WRITE) { "w" } else { "-" },
if self.contains(Self::USER_WRITE) && self.contains(Self::SET_USER_ID) {
"s"
} else if self.contains(Self::SET_USER_ID) {
"S"
} else if self.contains(Self::USER_EXECUTION) {
"x"
} else {
"-"
},
if self.contains(Self::GROUP_READ) { "r" } else { "-" },
if self.contains(Self::GROUP_WRITE) { "w" } else { "-" },
if self.contains(Self::GROUP_WRITE) && self.contains(Self::SET_GROUP_ID) {
"s"
} else if self.contains(Self::SET_GROUP_ID) {
"S"
} else if self.contains(Self::GROUP_EXECUTION) {
"x"
} else {
"-"
},
if self.contains(Self::OTHER_READ) { "r" } else { "-" },
if self.contains(Self::OTHER_WRITE) { "w" } else { "-" },
if self.contains(Self::OTHER_WRITE) { "x" } else { "-" }
)
}
}
impl From<Mode> for Permissions {
fn from(value: Mode) -> Self {
Self::from_bits_truncate(value.0)
}
}
impl From<Permissions> for Mode {
fn from(value: Permissions) -> Self {
Self(value.bits())
}
}
impl Permissions {
#[must_use]
pub const fn triad_for(&self, class: Class) -> Triad {
let (read_class, write_class, execution_class) = match class {
Class::Owner => (Self::USER_READ, Self::USER_WRITE, Self::USER_EXECUTION),
Class::Group => (Self::GROUP_READ, Self::GROUP_WRITE, Self::GROUP_EXECUTION),
Class::Other => (Self::OTHER_READ, Self::OTHER_WRITE, Self::OTHER_EXECUTION),
};
Triad {
read: self.contains(read_class),
write: self.contains(write_class),
execution: self.contains(execution_class),
}
}
}