use std::{ fs::{FileType, Metadata}, path::{Path, PathBuf}, }; use once_cell::unsync::OnceCell; enum DirEntryInner { Normal(ignore::DirEntry), BrokenSymlink(PathBuf), } pub struct DirEntry { inner: DirEntryInner, metadata: OnceCell>, } impl DirEntry { #[inline] pub fn normal(e: ignore::DirEntry) -> Self { Self { inner: DirEntryInner::Normal(e), metadata: OnceCell::new(), } } pub fn broken_symlink(path: PathBuf) -> Self { Self { inner: DirEntryInner::BrokenSymlink(path), metadata: OnceCell::new(), } } pub fn path(&self) -> &Path { match &self.inner { DirEntryInner::Normal(e) => e.path(), DirEntryInner::BrokenSymlink(pathbuf) => pathbuf.as_path(), } } pub fn into_path(self) -> PathBuf { match self.inner { DirEntryInner::Normal(e) => e.into_path(), DirEntryInner::BrokenSymlink(p) => p, } } pub fn file_type(&self) -> Option { match &self.inner { DirEntryInner::Normal(e) => e.file_type(), DirEntryInner::BrokenSymlink(_) => self.metadata().map(|m| m.file_type()), } } pub fn metadata(&self) -> Option<&Metadata> { self.metadata .get_or_init(|| match &self.inner { DirEntryInner::Normal(e) => e.metadata().ok(), DirEntryInner::BrokenSymlink(path) => path.symlink_metadata().ok(), }) .as_ref() } pub fn depth(&self) -> Option { match &self.inner { DirEntryInner::Normal(e) => Some(e.depth()), DirEntryInner::BrokenSymlink(_) => None, } } } impl PartialEq for DirEntry { #[inline] fn eq(&self, other: &Self) -> bool { self.path() == other.path() } } impl Eq for DirEntry {} impl PartialOrd for DirEntry { #[inline] fn partial_cmp(&self, other: &Self) -> Option { self.path().partial_cmp(other.path()) } } impl Ord for DirEntry { #[inline] fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.path().cmp(other.path()) } }