use super::{CapabilityError, Operation, failure};
use std::{ffi::OsString, iter::FusedIterator, path::PathBuf};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum EntryKind {
File,
Directory,
SymbolicLink,
Other,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DirectoryEntry {
pub name: OsString,
pub kind: EntryKind,
}
#[derive(Debug)]
pub struct DirectoryEntries {
inner: cap_std::fs::ReadDir,
path: PathBuf,
maximum: usize,
remaining: usize,
done: bool,
}
impl DirectoryEntries {
pub(super) const fn new(inner: cap_std::fs::ReadDir, path: PathBuf, maximum: usize) -> Self {
Self {
inner,
path,
maximum,
remaining: maximum,
done: false,
}
}
}
impl Iterator for DirectoryEntries {
type Item = Result<DirectoryEntry, CapabilityError>;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
return None;
}
let Some(entry) = self.inner.next() else {
self.done = true;
return None;
};
if self.remaining == 0 {
self.done = true;
return Some(Err(CapabilityError::EntryLimit {
path: self.path.clone(),
maximum: self.maximum,
}));
}
self.remaining -= 1;
Some(
entry
.map_err(|error| failure(Operation::ReadDirectory, &self.path, error))
.and_then(|entry| {
let name = entry.file_name();
let kind = entry.file_type().map_err(|error| {
failure(Operation::Metadata, &self.path.join(&name), error)
})?;
let kind = if kind.is_symlink() {
EntryKind::SymbolicLink
} else if kind.is_dir() {
EntryKind::Directory
} else if kind.is_file() {
EntryKind::File
} else {
EntryKind::Other
};
Ok(DirectoryEntry { name, kind })
}),
)
}
}
impl FusedIterator for DirectoryEntries {}