use std::fmt;
use std::ops::{BitOr, BitOrAssign};
use windows_sys::Win32::Storage::FileSystem::{
FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_OFFLINE, FILE_ATTRIBUTE_READONLY,
FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_TEMPORARY,
};
#[cfg(test)]
mod tests;
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct FileAttributes(u32);
macro_rules! attributes {
( $( $(#[$doc:meta])* $name:ident = $value:expr; )* ) => {
impl FileAttributes {
$( $(#[$doc])* pub const $name: Self = Self($value); )*
}
const NAMED: &[(&str, FileAttributes)] = &[ $( (stringify!($name), FileAttributes::$name), )* ];
};
}
attributes! {
ARCHIVE = FILE_ATTRIBUTE_ARCHIVE;
HIDDEN = FILE_ATTRIBUTE_HIDDEN;
OFFLINE = FILE_ATTRIBUTE_OFFLINE;
READONLY = FILE_ATTRIBUTE_READONLY;
SYSTEM = FILE_ATTRIBUTE_SYSTEM;
TEMPORARY = FILE_ATTRIBUTE_TEMPORARY;
}
impl FileAttributes {
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 FileAttributes {
type Output = Self;
fn bitor(self, other: Self) -> Self {
self.union(other)
}
}
impl BitOrAssign for FileAttributes {
fn bitor_assign(&mut self, other: Self) {
*self = self.union(other);
}
}
impl fmt::Debug for FileAttributes {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("FileAttributes(")?;
if self.is_empty() {
f.write_str("none")?;
} else {
let mut first = true;
for (name, _) in NAMED.iter().filter(|(_, member)| self.contains(*member)) {
if !first {
f.write_str(" | ")?;
}
first = false;
f.write_str(name)?;
}
}
f.write_str(")")
}
}