use char_enum::{char_enum_derive::FromChar, AsIter, FromChar, FromStrError, ToChar}; use enumflags2::{bitflags, BitFlag, FromBitsError}; use std::{error::Error, fmt::Display, num::ParseIntError, ops::BitOr, str::FromStr}; use enumflags2::BitFlags; use crate::utils::MapWhileRefExt; #[derive(Debug)] pub struct ParseModeError(String); impl ParseModeError { pub fn from_bits(bits: &str) -> Self { Self(format!("invalid mode: `{bits}`")) } } impl Display for ParseModeError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } } impl Error for ParseModeError {} impl From for ParseModeError { fn from(value: ParseIntError) -> Self { Self(value.to_string()) } } impl From> for ParseModeError { fn from(value: FromBitsError) -> Self { Self::from_bits(&value.invalid_bits().to_string()) } } #[bitflags] #[repr(u16)] #[derive(Clone, Copy, Debug)] pub enum Mode { IXOTH = 0x0001, IWOTH = 0x0002, IROTH = 0x0004, IXGRP = 0x0010, IWGRP = 0x0020, IRGRP = 0x0040, IXUSR = 0x0100, IWUSR = 0x0200, IRUSR = 0x0400, ISVTX = 0x1000, ISGID = 0x2000, ISUID = 0x4000, } impl Display for Mode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.to_string()) } } #[derive(Clone, Copy, Debug, Default)] pub struct ModeFlags(BitFlags); impl FromStr for ModeFlags { type Err = ParseModeError; fn from_str(s: &str) -> Result { let bits = u16::from_str(s)?; Ok(Self(BitFlags::from_bits(bits)?)) } } impl Display for ModeFlags { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } } #[derive(Clone, Copy, Debug, FromChar)] pub enum Operator { #[value = "-"] Sub, #[value = "+"] Add, #[value = "="] Eq, } impl Operator { pub fn split(s: &str) -> Option<(&str, char, &str)> { let mut result = None; for d in Operator::iter() { if let Some((a, b)) = s.split_once(d) { result = Some((a, d, b)); break; } } result } } #[bitflags] #[repr(u8)] #[derive(Clone, Copy, Debug, FromChar)] pub enum SymbolicMode { #[value = 'r'] Read, #[value = 'w'] Write, #[value = 'x'] Execute, #[value = 'X'] Search, #[value = 's'] SetId, #[value = 't'] Sticky, } #[bitflags] #[repr(u8)] #[derive(Clone, Copy, Debug, FromChar)] pub enum GroupId { #[value = 'u'] User, #[value = 'g'] Group, #[value = 'o'] Other, } #[derive(Clone, Debug)] pub struct Modes(BitFlags); impl Default for Modes { fn default() -> Self { Modes(BitFlags::::default()) } } impl FromStr for Modes { type Err = FromStrError; fn from_str(s: &str) -> Result { let flags = s .chars() .map_while_ref(|c: &char| T::from_char(*c)) .fold(BitFlags::default(), BitOr::bitor); Ok(Self(flags)) } } impl Display for Modes { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut iter = self.0.iter(); if let Some(head) = iter.next() { write!(f, "{head}")?; for item in iter { write!(f, "{item}")?; } } Ok(()) } } #[derive(Debug)] pub struct ParseSymbolicArgsError(FromStrError); impl Display for ParseSymbolicArgsError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } } impl Error for ParseSymbolicArgsError {} impl From for FromStrError { fn from(value: ParseSymbolicArgsError) -> Self { value.0 } } impl From for ParseSymbolicArgsError { fn from(value: FromStrError) -> Self { Self(value) } } #[derive(Clone, Debug)] pub enum SymbolicArgs { Group(Modes), Mode(Modes), } impl FromStr for SymbolicArgs { type Err = ParseSymbolicArgsError; fn from_str(s: &str) -> Result { match Modes::::from_str(s) { Ok(perms) => Ok(Self::Mode(perms)), Err(_) => match Modes::::from_str(s) { Ok(perms) => Ok(Self::Group(perms)), Err(_) => Err(FromStrError::new(format!("{} is not a valid argument", s)).into()), }, } } } impl Display for SymbolicArgs { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { SymbolicArgs::Group(modes) => write!(f, "{modes}"), SymbolicArgs::Mode(modes) => write!(f, "{modes}"), } } } #[derive(Clone, Debug)] pub enum ParseSymbolicError { Group(String), Operator(String), Mode(String), } impl Display for ParseSymbolicError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "{}", match self { Self::Group(e) => e, Self::Operator(e) => e, Self::Mode(e) => e, } ) } } impl Error for ParseSymbolicError {} impl From for ParseSymbolicError { fn from(value: ParseSymbolicArgsError) -> Self { Self::Mode(value.to_string()) } } #[derive(Clone, Debug)] pub struct SymbolicPermissions { groups: Modes, operator: Operator, mode: SymbolicArgs, } impl SymbolicPermissions { pub fn new(groups: Modes, operator: Operator, mode: SymbolicArgs) -> Self { Self { groups, operator, mode, } } } impl FromStr for SymbolicPermissions { type Err = ParseSymbolicError; fn from_str(s: &str) -> Result { match Operator::split(s) { Some((groups, operator, mode)) => { let groups = Modes::from_str(groups).map_err(|e| ParseSymbolicError::Group(e.to_string())); let operator = Operator::from_char(operator) .map_err(|o| ParseSymbolicError::Operator(o.to_string())); let mode = SymbolicArgs::from_str(mode)?; Ok(Self::new(groups?, operator?, mode)) } None => Err(ParseSymbolicError::Operator(format!( "received invalid permission syntax: {s}" ))), } } } impl Display for SymbolicPermissions { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}{}{}", self.groups, self.operator, self.mode) } } #[derive(Clone, Debug)] pub struct ParseOctalError(String); impl Display for ParseOctalError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } } impl Error for ParseOctalError {} impl From for ParseOctalError { fn from(value: ParseModeError) -> Self { Self(value.0) } } #[derive(Clone, Debug, Default)] pub struct OctalPermissions(ModeFlags); impl Display for OctalPermissions { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } } impl FromStr for OctalPermissions { type Err = ParseOctalError; fn from_str(s: &str) -> Result { Ok(Self(ModeFlags::from_str(s)?)) } } #[derive(Debug)] pub enum ParsePermissionsError { Symbolic(ParseSymbolicError), Octal(ParseOctalError), } impl Display for ParsePermissionsError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { ParsePermissionsError::Symbolic(e) => write!(f, "{e}"), ParsePermissionsError::Octal(e) => write!(f, "{e}"), } } } impl Error for ParsePermissionsError {} impl From for ParsePermissionsError { fn from(value: ParseSymbolicError) -> Self { Self::Symbolic(value) } } impl From for ParsePermissionsError { fn from(value: ParseOctalError) -> Self { Self::Octal(value) } } #[derive(Clone, Debug)] pub enum Permissions { Symbolic(SymbolicPermissions), Octal(OctalPermissions), } impl FromStr for Permissions { type Err = ParsePermissionsError; fn from_str(s: &str) -> Result { Ok(SymbolicPermissions::from_str(s) .map(Self::Symbolic) .or_else(|_| OctalPermissions::from_str(s).map(Self::Octal))?) } } impl Display for Permissions { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Permissions::Symbolic(v) => write!(f, "{v}"), Permissions::Octal(v) => write!(f, "{v}"), } } } #[cfg(test)] mod tests { use std::str::FromStr; use super::Permissions; #[test] fn it_works() { let a = Permissions::from_str("ug+w"); println!("{}", a.unwrap()); } }