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, hidden) = if self.options.collect_metadata
64 && file_type.is_file()
65 {
66 match entry.metadata() {
67 Ok(metadata) => (
68 Some(metadata.len()),
69 Some(crate::file_version::from_metadata(&metadata)),
70 Some(crate::hidden::is_hidden_metadata(&path, &metadata)),
71 ),
72 Err(source) => {
73 let error =
74 WalkError::new(path, depth, WalkOperation::ReadMetadata, source);
75 return Some(self.yield_error(error));
76 }
77 }
78 } else {
79 (None, None, None)
80 };
81 match self.visit(path, depth, Some(file_type), bytes, version, hidden) {
82 Ok(entry) => {
83 if let Some(entry) = self.prepare_entry(entry) {
84 return Some(Ok(entry));
85 }
86 continue 'walk;
87 }
88 Err(error) => return Some(self.yield_error(error)),
89 }
90 }
91 }
92 }
93}
94
95impl Walker {
96 fn take_root_entry(&mut self) -> Option<Result<WalkEntry, WalkError>> {
97 self.yield_root = false;
98 let root = self.root.as_ref().clone();
99 if self.plain_entries {
100 return Some(Ok(self.visit_plain(
101 root,
102 0,
103 self.root_file_type.expect("root metadata is present"),
104 )));
105 }
106 match self.visit(
107 root,
108 0,
109 Some(self.root_file_type.expect("root metadata is present")),
110 self.root_bytes,
111 self.root_version,
112 None,
113 ) {
114 Ok(entry) => self.prepare_entry(entry).map(Ok),
115 Err(error) => Some(self.yield_error(error)),
116 }
117 }
118
119 fn prepare_entry(&mut self, entry: WalkEntry) -> Option<WalkEntry> {
120 if entry.is_file()
121 && self.skip_stdout.is_some_and(|identity| {
122 crate::stdout::path_matches(entry.path(), identity).unwrap_or(false)
123 })
124 {
125 return None;
126 }
127 let accepted = self.filter.as_ref().is_none_or(|filter| filter(&entry));
128 if !accepted {
129 if entry.is_dir() {
130 self.skip_current_dir();
131 if entry.depth() == 0 {
132 self.finished = true;
133 }
134 }
135 return None;
136 }
137 if self.contents_first && entry.is_dir() && entry.skip_reason().is_none() {
138 if entry.depth() >= self.options.min_depth
139 && let Some(pending) = self.pending_directory.as_mut()
140 {
141 pending.post_entry = Some(entry);
142 }
143 return None;
144 }
145 if entry.depth() >= self.options.min_depth {
146 Some(entry)
147 } else {
148 None
149 }
150 }
151}