weavatrix_scan/content_visit.rs
1use crate::report::{
2 IgnoreSourceEvidence, ScanCacheStats, ScanTermination, ScanWarning, SkippedEntry,
3};
4use std::path::{Path, PathBuf};
5
6/// Controls whether a content visit retains selected-file evidence internally.
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum ContentVisitMode {
9 /// Retain compact selected-file evidence and compute a deterministic
10 /// revision.
11 Revision,
12 /// Emit bytes and counters without retaining selected-file evidence or
13 /// computing a revision.
14 Streaming,
15}
16
17/// Controls delivery from [`crate::Scanner::visit_content`].
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub enum ContentVisitControl {
20 /// Continue delivering the current file.
21 Continue,
22 /// Stop delivering chunks for this file while allowing required scanner
23 /// evidence work to finish.
24 SkipFile,
25 /// Cooperatively stop every content worker.
26 Quit,
27}
28
29/// Stable identity and discovery evidence for one selected file.
30#[derive(Debug, Clone, Copy)]
31pub struct ContentFile<'a> {
32 /// Root insertion index. A single-root [`crate::Scanner`] always uses zero.
33 pub root_index: usize,
34 /// Monotonic work sequence within this visit. Sort by `root_index` and
35 /// `relative` when results must be deterministic across runs.
36 pub sequence: u64,
37 pub root: &'a Path,
38 pub absolute: &'a Path,
39 pub relative: &'a str,
40 pub bytes: u64,
41}
42
43/// Result of verifying the file around its single content read.
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub enum ContentFileStatus {
46 Selected,
47 Binary,
48 Changed,
49}
50
51/// Events emitted from one bounded content worker.
52#[derive(Debug)]
53pub enum ContentVisitEvent<'a> {
54 /// The selected file was opened and its discovery evidence was verified.
55 FileStart {
56 worker_index: usize,
57 file: ContentFile<'a>,
58 },
59 /// A borrowed chunk from the scanner's one content read.
60 Chunk {
61 worker_index: usize,
62 file: ContentFile<'a>,
63 offset: u64,
64 bytes: &'a [u8],
65 },
66 /// The file read and post-read verification finished.
67 FileEnd {
68 worker_index: usize,
69 file: ContentFile<'a>,
70 status: ContentFileStatus,
71 bytes_read: u64,
72 content_hash: Option<&'a str>,
73 consumer_skipped: bool,
74 },
75}
76
77/// Summary of a parallel, one-pass selected-content visit.
78#[derive(Debug)]
79pub struct ContentVisitReport {
80 pub mode: ContentVisitMode,
81 pub root: PathBuf,
82 /// Candidates selected by traversal and ignore rules before content checks.
83 pub discovered: u64,
84 /// Files that completed content checks and remain selected.
85 pub completed: u64,
86 pub opened: u64,
87 pub chunks: u64,
88 pub bytes_read: u64,
89 pub bytes_emitted: u64,
90 pub consumer_skipped: u64,
91 pub stopped: bool,
92 pub skipped: Vec<SkippedEntry>,
93 pub warnings: Vec<ScanWarning>,
94 pub ignore_sources: Vec<IgnoreSourceEvidence>,
95 pub revision: String,
96 pub complete: bool,
97 pub termination: Option<ScanTermination>,
98 pub portable: bool,
99 pub cache: ScanCacheStats,
100}
101
102/// Ordered summaries from a multi-root content visit.
103#[derive(Debug)]
104pub struct MultiContentVisitReport {
105 /// Reports remain in the same order as roots were added.
106 pub reports: Vec<ContentVisitReport>,
107}
108
109impl MultiContentVisitReport {
110 #[must_use]
111 pub const fn len(&self) -> usize {
112 self.reports.len()
113 }
114
115 #[must_use]
116 pub const fn is_empty(&self) -> bool {
117 self.reports.is_empty()
118 }
119}
120
121/// Content and removals produced by a safe file-only watcher plan.
122#[derive(Debug)]
123pub struct ChangedContentVisitReport {
124 /// Evidence for the changed files that still exist and remain selected.
125 ///
126 /// Its revision describes this changed-file subset, not the complete
127 /// repository manifest.
128 pub content: ContentVisitReport,
129 /// Stable normalized paths that disappeared from the repository.
130 pub removed: Vec<String>,
131}
132
133/// Result of attempting a traversal-free watcher content visit.
134#[derive(Debug)]
135pub enum ChangedContentVisitOutcome {
136 /// Only changed file paths were matched, opened, and visited.
137 Visited(Box<ChangedContentVisitReport>),
138 /// The plan can affect directory structure or selection and therefore
139 /// requires the caller to perform a complete scan.
140 FullRescanRequired,
141}