Skip to main content

plot/lib/logic/path/
paths_result.rs

1use std::collections::HashSet;
2
3// Wciągamy czyste, domenowe nazwy
4use crate::lib::logic::{
5	AnchoredPathsDatum,
6	PattEnvIndex,
7	PatternsToApply,
8	ScannedToApply,
9	TabColumn,
10	TabPathStructure,
11	TabSortBy,
12	TabSortOrder,
13	TabSpec,
14	TableData,
15	TableOutput,
16};
17
18// ============================================================================
19// SEMANTYKA TRUE/FALSE
20// ============================================================================
21
22pub trait MatchLabel {
23	fn label() -> &'static str;
24}
25
26#[derive(Debug, Clone)]
27pub struct Matched;
28#[derive(Debug, Clone)]
29pub struct Mismatched;
30
31impl MatchLabel for Matched {
32	fn label() -> &'static str { "✔" } // ✔️
33}
34
35impl MatchLabel for Mismatched {
36	fn label() -> &'static str { "✖" } // ✖️
37}
38
39/// ============================================================================
40/// FILTER LIST
41/// ============================================================================
42
43#[derive(Debug, Clone)]
44pub struct Partition<L: MatchLabel> {
45	pub paths: Vec<String>,
46	pub label: &'static str,
47	pub entry: AnchoredPathsDatum,
48	pub _marker: std::marker::PhantomData<L>,
49}
50
51// ============================================================================
52// ENV INDEX IMPLEMENTATION (Zero-copy, Binary Search)
53// ============================================================================
54
55struct EnvIndex<'a> {
56	pub dirs: HashSet<&'a str>,
57	pub files: Vec<&'a str>,
58}
59
60impl<'a> PattEnvIndex for EnvIndex<'a> {
61	fn has_dir(&self, dir: &str) -> bool { self.dirs.contains(dir) }
62
63	fn has_file_with_prefix(&self, prefix: &str) -> bool {
64		let start = self.files.partition_point(|&f| f < prefix);
65		start < self.files.len() && self.files[start].starts_with(prefix)
66	}
67
68	fn any_file_in_dir(&self, dir: &str, check: &mut dyn FnMut(&str) -> bool) -> bool {
69		let start = self.files.partition_point(|&f| f < dir);
70		for &f in &self.files[start..] {
71			if !f.starts_with(dir) {
72				break;
73			}
74			if check(f) {
75				return true;
76			}
77		}
78		false
79	}
80}
81
82// ============================================================================
83// RESULT SCAN PATTERNS
84// ============================================================================
85
86#[derive(Debug, Clone)]
87pub struct PartitioningResult {
88	pub scanner: ScannedToApply,
89	pub patterns: PatternsToApply,
90
91	pub m: Partition<Matched>,
92	pub x: Partition<Mismatched>,
93
94	// Przechowuje recepturę jak zbudować wyjściową tabelę
95	pub spec: TabSpec,
96}
97
98impl PartitioningResult {
99	pub fn new(scanner: ScannedToApply, patterns: PatternsToApply) -> Self {
100		let env_index = EnvIndex {
101			dirs: scanner.dirs.iter().map(|n| n.str.as_str()).collect(),
102			files: scanner.files.iter().map(|n| n.str.as_str()).collect(),
103		};
104
105		let mut m_vec = Vec::new();
106		let mut x_vec = Vec::new();
107
108		let all_paths = scanner.files.iter().chain(scanner.dirs.iter());
109
110		for node in all_paths {
111			let p = node.str.as_str();
112			if patterns.is_match(p, &env_index) {
113				m_vec.push(node.str.clone());
114			} else {
115				x_vec.push(node.str.clone());
116			}
117		}
118
119		let entry = scanner.stat.relation.clone();
120
121		Self {
122			scanner,
123			patterns,
124			m: Partition {
125				paths: m_vec,
126				label: Matched::label(),
127				entry: entry.clone(),
128				_marker: std::marker::PhantomData,
129			},
130			x: Partition { paths: x_vec, label: Mismatched::label(), entry, _marker: std::marker::PhantomData },
131			spec: TabSpec::default(),
132		}
133	}
134
135	// ============================================================================
136	// BUILDER API (Konfiguracja specyfikacji w miejscu)
137	// ============================================================================
138
139	pub fn sort(mut self, by: TabSortBy, order: TabSortOrder, structure: TabPathStructure) -> Self {
140		self.spec = self.spec.sort(by, order, structure);
141		self
142	}
143
144	pub fn columns(mut self, cols: &[TabColumn]) -> Self {
145		self.spec = self.spec.columns(cols);
146		self
147	}
148
149	pub fn trim(mut self, size: usize, page: Option<usize>) -> Self {
150		self.spec = self.spec.trim(size, page);
151		self
152	}
153
154	// ============================================================================
155	// LENIWA MATERIALIZACJA (Fizyczny odczyt FS na wybranej grupie)
156	// ============================================================================
157
158	pub fn build_matched(&self) -> TableOutput {
159		TableData::gather(&self.m)
160			.sort(self.spec.sort_by, self.spec.sort_order, self.spec.structure)
161			.into_output(&self.spec)
162	}
163
164	pub fn build_mismatched(&self) -> TableOutput {
165		TableData::gather(&self.x)
166			.sort(self.spec.sort_by, self.spec.sort_order, self.spec.structure)
167			.into_output(&self.spec)
168	}
169}