Skip to main content

weavatrix_scan/stateful_walk/
serial.rs

1use 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}