use std::fmt;
use std::ops::{BitOr, BitOrAssign};
use windows_sys::Win32::Storage::FileSystem::{
DELETE, FILE_EXECUTE, FILE_READ_ATTRIBUTES, FILE_READ_EA, FILE_WRITE_ATTRIBUTES, FILE_WRITE_EA,
READ_CONTROL, SYNCHRONIZE, WRITE_DAC, WRITE_OWNER,
};
use windows_sys::Win32::System::SystemServices::ACCESS_SYSTEM_SECURITY;
#[cfg(test)]
mod tests;
#[derive(Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct FileRights(u32);
macro_rules! rights {
( $( $(#[$doc:meta])* $name:ident = $value:expr; )* ) => {
impl FileRights {
$( $(#[$doc])* pub const $name: Self = Self($value); )*
}
const NAMED: &[(&str, FileRights)] = &[ $( (stringify!($name), FileRights::$name), )* ];
};
}
rights! {
READ_ATTRIBUTES = FILE_READ_ATTRIBUTES;
WRITE_ATTRIBUTES = FILE_WRITE_ATTRIBUTES;
READ_EA = FILE_READ_EA;
WRITE_EA = FILE_WRITE_EA;
EXECUTE = FILE_EXECUTE;
DELETE = DELETE;
READ_CONTROL = READ_CONTROL;
WRITE_DAC = WRITE_DAC;
WRITE_OWNER = WRITE_OWNER;
SYNCHRONIZE = SYNCHRONIZE;
ACCESS_SYSTEM_SECURITY = ACCESS_SYSTEM_SECURITY;
}
impl FileRights {
pub const NONE: Self = Self(0);
#[must_use]
pub const fn union(self, other: Self) -> Self {
Self(self.0 | other.0)
}
#[must_use]
pub const fn contains(self, other: Self) -> bool {
self.0 & other.0 == other.0
}
#[must_use]
pub const fn is_empty(self) -> bool {
self.0 == 0
}
pub(super) const fn bits(self) -> u32 {
self.0
}
}
impl BitOr for FileRights {
type Output = Self;
fn bitor(self, other: Self) -> Self {
self.union(other)
}
}
impl BitOrAssign for FileRights {
fn bitor_assign(&mut self, other: Self) {
*self = self.union(other);
}
}
impl fmt::Debug for FileRights {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("FileRights(")?;
if self.is_empty() {
f.write_str("none")?;
} else {
let mut first = true;
for (name, _) in NAMED.iter().filter(|(_, right)| self.contains(*right)) {
if !first {
f.write_str(" | ")?;
}
first = false;
f.write_str(name)?;
}
}
f.write_str(")")
}
}