weavatrix_scan/
walk_iter.rs1use crate::walk_types::{WalkEntry, WalkError, WalkOperation};
2use crate::walker::Walker;
3
4impl Iterator for Walker {
5 type Item = Result<WalkEntry, WalkError>;
6
7 #[inline]
8 fn next(&mut self) -> Option<Self::Item> {
9 'walk: loop {
10 if self.finished {
11 return None;
12 }
13 if let Some(entry) = self.deferred_entry.take() {
14 return Some(Ok(entry));
15 }
16 if self.yield_root {
17 if let Some(entry) = self.take_root_entry() {
18 return Some(entry);
19 }
20 continue;
21 }
22 if let Some(error) = self.schedule_pending_directory() {
23 return Some(self.yield_error(error));
24 }
25 loop {
26 let frame = self.frames.last_mut()?;
27 let depth = frame.depth + 1;
28 let entry = match frame.entries.next() {
29 Some(Ok(entry)) => entry,
30 Some(Err(source)) => {
31 let error =
32 WalkError::new(&frame.path, depth, WalkOperation::ReadEntry, source);
33 return Some(self.yield_error(error));
34 }
35 None => {
36 let was_open = frame.entries.is_open();
37 let identity = frame.identity;
38 let post_entry = self.frames.pop().expect("last frame exists").post_entry;
39 if was_open {
40 self.open_handles -= 1;
41 }
42 if let Some(identity) = identity {
43 self.active_directories.remove(&identity);
44 }
45 if let Some(entry) = post_entry {
46 return Some(Ok(entry));
47 }
48 continue;
49 }
50 };
51 let path = entry.path();
52 let file_type = match entry.file_type() {
53 Ok(file_type) => file_type,
54 Err(source) => {
55 let error =
56 WalkError::new(path, depth, WalkOperation::ReadMetadata, source);
57 return Some(self.yield_error(error));
58 }
59 };
60 if self.plain_entries {
61 return Some(Ok(self.visit_plain(path, depth, file_type)));
62 }
63 let (bytes, version) = if self.options.collect_metadata && file_type.is_file() {
64 match entry.metadata() {
65 Ok(metadata) => (
66 Some(metadata.len()),
67 Some(crate::file_version::from_metadata(&metadata)),
68 ),
69 Err(source) => {
70 let error =
71 WalkError::new(path, depth, WalkOperation::ReadMetadata, source);
72 return Some(self.yield_error(error));
73 }
74 }
75 } else {
76 (None, None)
77 };
78 match self.visit(path, depth, Some(file_type), bytes, version) {
79 Ok(entry) => {
80 if let Some(entry) = self.prepare_entry(entry) {
81 return Some(Ok(entry));
82 }
83 continue 'walk;
84 }
85 Err(error) => return Some(self.yield_error(error)),
86 }
87 }
88 }
89 }
90}
91
92impl Walker {
93 fn take_root_entry(&mut self) -> Option<Result<WalkEntry, WalkError>> {
94 self.yield_root = false;
95 let root = self.root.as_ref().clone();
96 if self.plain_entries {
97 return Some(Ok(self.visit_plain(
98 root,
99 0,
100 self.root_file_type.expect("root metadata is present"),
101 )));
102 }
103 match self.visit(
104 root,
105 0,
106 Some(self.root_file_type.expect("root metadata is present")),
107 self.root_bytes,
108 self.root_version,
109 ) {
110 Ok(entry) => self.prepare_entry(entry).map(Ok),
111 Err(error) => Some(self.yield_error(error)),
112 }
113 }
114
115 fn prepare_entry(&mut self, entry: WalkEntry) -> Option<WalkEntry> {
116 if entry.is_file()
117 && self.skip_stdout.is_some_and(|identity| {
118 crate::stdout::path_matches(entry.path(), identity).unwrap_or(false)
119 })
120 {
121 return None;
122 }
123 let accepted = self.filter.as_ref().is_none_or(|filter| filter(&entry));
124 if !accepted {
125 if entry.is_dir() {
126 self.skip_current_dir();
127 if entry.depth() == 0 {
128 self.finished = true;
129 }
130 }
131 return None;
132 }
133 if self.contents_first && entry.is_dir() && entry.skip_reason().is_none() {
134 if entry.depth() >= self.options.min_depth
135 && let Some(pending) = self.pending_directory.as_mut()
136 {
137 pending.post_entry = Some(entry);
138 }
139 return None;
140 }
141 if entry.depth() >= self.options.min_depth {
142 Some(entry)
143 } else {
144 None
145 }
146 }
147}