weavatrix_scan/stateful_walk/
serial.rs1use super::{
2 Arc, DirectoryFrame, DirectoryTask, HashSet, StatefulWalkBuilder, StatefulWalkEntry,
3 StatefulWalker, WalkError, Walker,
4};
5
6impl<R, E> StatefulWalker<R, E>
7where
8 R: Clone + Send + 'static,
9 E: Default + Send + 'static,
10{
11 pub(super) fn new(builder: StatefulWalkBuilder<R, E>) -> Result<Self, WalkError> {
12 let options = builder.options.normalized();
13 let mut root_options = options;
14 root_options.min_depth = 0;
15 let mut walker = Walker::with_options(&builder.root, root_options)?;
16 let root_file_system = walker.root_file_system;
17 let root = Arc::clone(&walker.root);
18 let root_entry = walker.next().expect("a validated root yields one entry")?;
19 let identity = root_entry.directory_identity();
20 let mut ancestors = HashSet::new();
21 if let Some(identity) = identity {
22 ancestors.insert(identity);
23 }
24 let can_descend = root_entry.is_dir() && root_entry.skip_reason().is_none();
25 let root_entry = (root_entry.depth() >= options.min_depth).then(|| StatefulWalkEntry {
26 read_children: can_descend,
27 entry: root_entry,
28 state: E::default(),
29 });
30 let pending = can_descend.then(|| DirectoryTask {
31 path: root.as_ref().clone(),
32 depth: 0,
33 identity,
34 ancestors,
35 read_state: builder.root_read_dir_state,
36 });
37 Ok(Self {
38 root,
39 root_file_system,
40 options,
41 processor: builder.processor,
42 root_entry,
43 pending,
44 frames: Vec::new(),
45 })
46 }
47
48 fn read_directory(&self, mut task: DirectoryTask<R>) -> DirectoryFrame<R, E> {
49 let mut worker_options = self.options;
50 worker_options.error_policy = crate::walk_types::ErrorPolicy::Continue;
51 worker_options.min_depth = 0;
52 worker_options.max_open = 1;
53 worker_options.max_depth = Some(
54 self.options
55 .max_depth
56 .unwrap_or(task.depth.saturating_add(1))
57 .min(task.depth.saturating_add(1)),
58 );
59 let mut walker = Walker::from_known_directory_with_ancestry(
60 &self.root,
61 task.path.clone(),
62 task.depth,
63 worker_options,
64 self.root_file_system,
65 task.identity,
66 task.ancestors.clone(),
67 );
68 let mut entries = Vec::new();
69 while let Some(item) = walker.next() {
70 match item {
71 Ok(mut entry) => {
72 if entry.is_dir()
73 && entry.skip_reason() == Some(crate::WalkSkipReason::MaxDepth)
74 && self
75 .options
76 .max_depth
77 .is_none_or(|maximum| entry.depth() < maximum)
78 {
79 entry.clear_depth_skip();
80 }
81 if entry.is_dir() {
82 walker.skip_current_dir();
83 }
84 entries.push(Ok(StatefulWalkEntry {
85 read_children: entry.is_dir() && entry.skip_reason().is_none(),
86 entry,
87 state: E::default(),
88 }));
89 }
90 Err(error) => entries.push(Err(error)),
91 }
92 }
93 if let Some(processor) = self.processor.as_ref() {
94 processor(task.depth, &task.path, &mut task.read_state, &mut entries);
95 }
96 DirectoryFrame {
97 entries: entries.into_iter(),
98 child_state: task.read_state,
99 ancestors: task.ancestors,
100 }
101 }
102}
103
104impl<R, E> Iterator for StatefulWalker<R, E>
105where
106 R: Clone + Send + 'static,
107 E: Default + Send + 'static,
108{
109 type Item = Result<StatefulWalkEntry<E>, WalkError>;
110
111 fn next(&mut self) -> Option<Self::Item> {
112 if let Some(root_entry) = self.root_entry.take() {
113 return Some(Ok(root_entry));
114 }
115 loop {
116 if let Some(task) = self.pending.take() {
117 let frame = self.read_directory(task);
118 self.frames.push(frame);
119 }
120 let frame = self.frames.last_mut()?;
121 let Some(item) = frame.entries.next() else {
122 self.frames.pop();
123 continue;
124 };
125 if let Ok(entry) = &item
126 && entry.read_children
127 {
128 let identity = entry.entry.directory_identity();
129 let mut ancestors = frame.ancestors.clone();
130 if let Some(identity) = identity {
131 ancestors.insert(identity);
132 }
133 self.pending = Some(DirectoryTask {
134 path: entry.path().to_path_buf(),
135 depth: entry.depth(),
136 identity,
137 ancestors,
138 read_state: frame.child_state.clone(),
139 });
140 }
141 let visible = item
142 .as_ref()
143 .map_or(true, |entry| entry.depth() >= self.options.min_depth);
144 if visible {
145 return Some(item);
146 }
147 }
148 }
149}