use crate::walk_types::{WalkEntry, WalkError, WalkOperation};
use crate::walker::Walker;
impl Iterator for Walker {
type Item = Result<WalkEntry, WalkError>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
'walk: loop {
if self.finished {
return None;
}
if let Some(entry) = self.deferred_entry.take() {
return Some(Ok(entry));
}
if self.yield_root {
if let Some(entry) = self.take_root_entry() {
return Some(entry);
}
continue;
}
if let Some(error) = self.schedule_pending_directory() {
return Some(self.yield_error(error));
}
loop {
let frame = self.frames.last_mut()?;
let depth = frame.depth + 1;
let entry = match frame.entries.next() {
Some(Ok(entry)) => entry,
Some(Err(source)) => {
let error =
WalkError::new(&frame.path, depth, WalkOperation::ReadEntry, source);
return Some(self.yield_error(error));
}
None => {
let was_open = frame.entries.is_open();
let identity = frame.identity;
let post_entry = self.frames.pop().expect("last frame exists").post_entry;
if was_open {
self.open_handles -= 1;
}
if let Some(identity) = identity {
self.active_directories.remove(&identity);
}
if let Some(entry) = post_entry {
return Some(Ok(entry));
}
continue;
}
};
let path = entry.path();
let file_type = match entry.file_type() {
Ok(file_type) => file_type,
Err(source) => {
let error =
WalkError::new(path, depth, WalkOperation::ReadMetadata, source);
return Some(self.yield_error(error));
}
};
if self.plain_entries {
return Some(Ok(self.visit_plain(path, depth, file_type)));
}
let (bytes, version, hidden) = if self.options.collect_metadata
&& file_type.is_file()
{
match entry.metadata() {
Ok(metadata) => (
Some(metadata.len()),
Some(crate::file_version::from_metadata(&metadata)),
Some(crate::hidden::is_hidden_metadata(&path, &metadata)),
),
Err(source) => {
let error =
WalkError::new(path, depth, WalkOperation::ReadMetadata, source);
return Some(self.yield_error(error));
}
}
} else {
(None, None, None)
};
match self.visit(path, depth, Some(file_type), bytes, version, hidden) {
Ok(entry) => {
if let Some(entry) = self.prepare_entry(entry) {
return Some(Ok(entry));
}
continue 'walk;
}
Err(error) => return Some(self.yield_error(error)),
}
}
}
}
}
impl Walker {
fn take_root_entry(&mut self) -> Option<Result<WalkEntry, WalkError>> {
self.yield_root = false;
let root = self.root.as_ref().clone();
if self.plain_entries {
return Some(Ok(self.visit_plain(
root,
0,
self.root_file_type.expect("root metadata is present"),
)));
}
match self.visit(
root,
0,
Some(self.root_file_type.expect("root metadata is present")),
self.root_bytes,
self.root_version,
None,
) {
Ok(entry) => self.prepare_entry(entry).map(Ok),
Err(error) => Some(self.yield_error(error)),
}
}
fn prepare_entry(&mut self, entry: WalkEntry) -> Option<WalkEntry> {
if entry.is_file()
&& self.skip_stdout.is_some_and(|identity| {
crate::stdout::path_matches(entry.path(), identity).unwrap_or(false)
})
{
return None;
}
let accepted = self.filter.as_ref().is_none_or(|filter| filter(&entry));
if !accepted {
if entry.is_dir() {
self.skip_current_dir();
if entry.depth() == 0 {
self.finished = true;
}
}
return None;
}
if self.contents_first && entry.is_dir() && entry.skip_reason().is_none() {
if entry.depth() >= self.options.min_depth
&& let Some(pending) = self.pending_directory.as_mut()
{
pending.post_entry = Some(entry);
}
return None;
}
if entry.depth() >= self.options.min_depth {
Some(entry)
} else {
None
}
}
}