#![warn(missing_docs)]
#[cfg(feature = "mode-t-conversion")]
mod mode_t_conversion_feature;
#[cfg(unix)]
use std::os::unix::fs::FileTypeExt;
use std::{fmt, fs, io, path::Path};
#[cfg(feature = "mode-t-conversion")]
pub use mode_t_conversion_feature::*;
#[rustfmt::skip]
#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy, Ord, PartialOrd)]
pub enum FileType {
Regular,
Directory,
Symlink,
#[cfg(unix)] BlockDevice,
#[cfg(unix)] CharDevice,
#[cfg(unix)] Fifo,
#[cfg(unix)] Socket,
}
impl FileType {
pub fn read_at(path: impl AsRef<Path>) -> io::Result<Self> {
let fs_file_type = fs::metadata(path.as_ref())?.file_type();
let result = FileType::from(fs_file_type);
Ok(result)
}
pub fn symlink_read_at(path: impl AsRef<Path>) -> io::Result<Self> {
let fs_file_type = fs::symlink_metadata(path.as_ref())?.file_type();
let result = FileType::from(fs_file_type);
Ok(result)
}
pub fn is_regular(&self) -> bool {
matches!(self, FileType::Regular)
}
pub fn is_directory(&self) -> bool {
matches!(self, FileType::Directory)
}
pub fn is_symlink(&self) -> bool {
matches!(self, FileType::Symlink)
}
#[cfg(unix)]
pub fn is_block_device(&self) -> bool {
matches!(self, FileType::BlockDevice)
}
#[cfg(unix)]
pub fn is_char_device(&self) -> bool {
matches!(self, FileType::CharDevice)
}
#[cfg(unix)]
pub fn is_fifo(&self) -> bool {
matches!(self, FileType::Fifo)
}
#[cfg(unix)]
pub fn is_socket(&self) -> bool {
matches!(self, FileType::Socket)
}
}
impl From<fs::FileType> for FileType {
fn from(ft: fs::FileType) -> Self {
#[cfg(unix)]
let result = {
if ft.is_file() {
FileType::Regular
} else if ft.is_dir() {
FileType::Directory
} else if ft.is_symlink() {
FileType::Symlink
} else if ft.is_block_device() {
FileType::BlockDevice
} else if ft.is_char_device() {
FileType::CharDevice
} else if ft.is_fifo() {
FileType::Fifo
} else if ft.is_socket() {
FileType::Socket
} else {
unreachable!("file_type_enum: unexpected file type: {:?}.", ft)
}
};
#[cfg(not(unix))]
let result = {
if ft.is_file() {
FileType::Regular
} else if ft.is_dir() {
FileType::Directory
} else if ft.is_symlink() {
FileType::Symlink
} else {
unreachable!("file_type_enum: unexpected file type: {:?}.", ft)
}
};
result
}
}
impl From<fs::Metadata> for FileType {
fn from(metadata: fs::Metadata) -> Self {
metadata.file_type().into()
}
}
impl fmt::Display for FileType {
#[rustfmt::skip]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
FileType::Regular => write!(f, "regular file"),
FileType::Directory => write!(f, "directory"),
FileType::Symlink => write!(f, "symbolic link"),
#[cfg(unix)] FileType::BlockDevice => write!(f, "block device"),
#[cfg(unix)] FileType::CharDevice => write!(f, "char device"),
#[cfg(unix)] FileType::Fifo => write!(f, "FIFO"),
#[cfg(unix)] FileType::Socket => write!(f, "socket"),
}
}
}
#[cfg(test)]
mod tests {
use super::FileType;
#[test]
fn test_with_this_repository_structured() {
let this_file = FileType::read_at("src/lib.rs").unwrap();
assert!(this_file.is_regular());
}
}