Skip to main content

weavatrix_scan/parallel/
visit.rs

1use super::ParallelWalker;
2use super::dynamic;
3use super::visit_worker::visit_serial;
4use crate::control::CancellationToken;
5use crate::walker::{WalkEntry, WalkError};
6
7/// A streaming event emitted from a parallel traversal worker.
8#[derive(Debug)]
9pub enum WalkEvent<'a> {
10    Entry(&'a WalkEntry),
11    Error(&'a WalkError),
12}
13
14/// Controls traversal after a streaming visitor handles an event.
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum WalkControl {
17    Continue,
18    /// Prevents descent when the current event is a directory entry.
19    Skip,
20    /// Cooperatively stops every traversal worker.
21    Quit,
22}
23
24/// Summary of a streaming parallel traversal.
25#[derive(Debug)]
26pub struct ParallelVisitReport {
27    pub visited: u64,
28    pub errors: Vec<WalkError>,
29    pub quit: bool,
30    pub cancelled: bool,
31}
32
33impl ParallelWalker {
34    /// Visits entries directly on traversal workers without collecting paths.
35    ///
36    /// Visitor calls may run concurrently and their order is intentionally
37    /// unspecified. Use [`Self::walk`] when deterministic collected order is
38    /// required.
39    ///
40    /// # Errors
41    ///
42    /// Returns a root error or the first traversal error under
43    /// `ErrorPolicy::Abort`.
44    ///
45    /// # Panics
46    ///
47    /// Panics if the visitor or an internal traversal worker panics.
48    pub fn visit<F>(self, visitor: F) -> Result<ParallelVisitReport, WalkError>
49    where
50        F: for<'entry> Fn(WalkEvent<'entry>) -> WalkControl + Send + Sync + 'static,
51    {
52        self.visit_with_cancellation(&CancellationToken::new(), visitor)
53    }
54
55    /// Streaming parallel traversal with cooperative cancellation.
56    ///
57    /// # Errors
58    ///
59    /// Returns a root error or the first traversal error under
60    /// `ErrorPolicy::Abort`.
61    ///
62    /// # Panics
63    ///
64    /// Panics if the visitor or an internal traversal worker panics.
65    pub fn visit_with_cancellation<F>(
66        mut self,
67        cancellation: &CancellationToken,
68        visitor: F,
69    ) -> Result<ParallelVisitReport, WalkError>
70    where
71        F: for<'entry> Fn(WalkEvent<'entry>) -> WalkControl + Send + Sync + 'static,
72    {
73        self.options = self.options.normalized();
74        if self.runtime.is_worker_thread() {
75            visit_serial(
76                &self.root,
77                self.options,
78                self.skip_stdout,
79                cancellation,
80                visitor,
81            )
82        } else {
83            dynamic::visit(
84                &self.root,
85                self.options,
86                self.parallelism,
87                &self.runtime,
88                self.skip_stdout,
89                cancellation,
90                visitor,
91            )
92        }
93    }
94}