use nix::sys::stat::SFlag;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum EntryKind {
File,
Directory,
Symlink,
Other(u32),
}
impl EntryKind {
#[must_use]
pub fn from_mode(mode: u32) -> Self {
match mode & SFlag::S_IFMT.bits() {
x if x == SFlag::S_IFREG.bits() => Self::File,
x if x == SFlag::S_IFDIR.bits() => Self::Directory,
x if x == SFlag::S_IFLNK.bits() => Self::Symlink,
0 => Self::File,
other => Self::Other(other),
}
}
#[must_use]
pub fn is_file(&self) -> bool {
matches!(self, Self::File)
}
#[must_use]
pub fn is_directory(&self) -> bool {
matches!(self, Self::Directory)
}
#[must_use]
pub fn is_symlink(&self) -> bool {
matches!(self, Self::Symlink)
}
}
impl std::fmt::Display for EntryKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::File => write!(f, "file"),
Self::Directory => write!(f, "directory"),
Self::Symlink => write!(f, "symlink"),
Self::Other(mode) => write!(f, "unknown({mode:#o})"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn file_mode() {
assert_eq!(EntryKind::from_mode(0o100644), EntryKind::File);
assert_eq!(EntryKind::from_mode(0o100755), EntryKind::File);
}
#[test]
fn directory_mode() {
assert_eq!(EntryKind::from_mode(0o040755), EntryKind::Directory);
assert_eq!(EntryKind::from_mode(0o040000), EntryKind::Directory);
}
#[test]
fn symlink_mode() {
assert_eq!(EntryKind::from_mode(0o120777), EntryKind::Symlink);
assert_eq!(EntryKind::from_mode(0o120000), EntryKind::Symlink);
}
#[test]
fn zero_mode_defaults_to_file() {
assert_eq!(EntryKind::from_mode(0), EntryKind::File);
}
#[test]
fn unknown_mode() {
let kind = EntryKind::from_mode(0o060644);
assert_eq!(kind, EntryKind::Other(0o060000));
}
#[test]
fn predicates() {
assert!(EntryKind::File.is_file());
assert!(!EntryKind::File.is_directory());
assert!(!EntryKind::File.is_symlink());
assert!(!EntryKind::Directory.is_file());
assert!(EntryKind::Directory.is_directory());
assert!(!EntryKind::Directory.is_symlink());
assert!(!EntryKind::Symlink.is_file());
assert!(!EntryKind::Symlink.is_directory());
assert!(EntryKind::Symlink.is_symlink());
}
#[test]
fn display() {
assert_eq!(format!("{}", EntryKind::File), "file");
assert_eq!(format!("{}", EntryKind::Directory), "directory");
assert_eq!(format!("{}", EntryKind::Symlink), "symlink");
assert_eq!(
format!("{}", EntryKind::Other(0o060000)),
"unknown(0o60000)"
);
}
}