1use std::collections::BTreeMap;
2use std::sync::Arc;
3
4use super::FormulaPlaneMode;
5use super::arena::AstNodeId;
6use super::formula_source::{SourceFamilyId, SourceFormulaOrder};
7
8#[derive(Clone, Debug)]
9pub struct FormulaIngestRecord {
10 pub row: u32,
11 pub col: u32,
12 pub ast_id: AstNodeId,
13 pub formula_text: Option<Arc<str>>,
14 pub(crate) source_order: Option<SourceFormulaOrder>,
15 pub(crate) source_family: Option<SourceFamilyId>,
16 pub(crate) partition_owner: Option<SourceFamilyId>,
17 pub(crate) member_anchor: Option<(u32, u32)>,
21}
22
23impl FormulaIngestRecord {
24 pub fn new(row: u32, col: u32, ast_id: AstNodeId, formula_text: Option<Arc<str>>) -> Self {
25 Self {
26 row,
27 col,
28 ast_id,
29 formula_text,
30 source_order: None,
31 source_family: None,
32 partition_owner: None,
33 member_anchor: None,
34 }
35 }
36
37 pub(crate) fn member(row: u32, col: u32, template: AstNodeId, anchor: (u32, u32)) -> Self {
39 Self {
40 member_anchor: Some(anchor),
41 ..Self::new(row, col, template, None)
42 }
43 }
44
45 pub fn is_family_member(&self) -> bool {
48 self.member_anchor.is_some()
49 }
50
51 pub(crate) fn with_source_proof(
52 mut self,
53 source_order: SourceFormulaOrder,
54 source_family: Option<SourceFamilyId>,
55 partition_owner: Option<SourceFamilyId>,
56 ) -> Self {
57 self.source_order = Some(source_order);
58 self.source_family = source_family;
59 self.partition_owner = partition_owner;
60 self
61 }
62}
63
64#[derive(Debug, Default)]
70pub struct FormulaFamilyGrouper {
71 pub(crate) by_col: rustc_hash::FxHashMap<u32, (u32, GroupedFamily)>,
73 pub(crate) last: Option<(u32, u32, GroupedFamily)>,
75 pub(crate) members: u64,
77}
78
79impl FormulaFamilyGrouper {
80 pub fn new() -> Self {
81 Self::default()
82 }
83
84 pub fn members(&self) -> u64 {
86 self.members
87 }
88
89 pub(crate) fn note(&mut self, row0: u32, col0: u32, family: GroupedFamily) {
90 self.by_col.insert(col0, (row0, family.clone()));
91 self.last = Some((row0, col0, family));
92 }
93}
94
95#[derive(Clone, Debug)]
100pub(crate) struct GroupedFamily {
101 pub(crate) template: AstNodeId,
102 pub(crate) anchor: (u32, u32),
103 pub(crate) rendered: Option<Option<Arc<[bool]>>>,
104}
105
106#[derive(Clone, Debug)]
107pub struct FormulaIngestBatch {
108 pub sheet_name: String,
109 pub formulas: Vec<FormulaIngestRecord>,
110}
111
112impl FormulaIngestBatch {
113 pub fn new(sheet_name: impl Into<String>, formulas: Vec<FormulaIngestRecord>) -> Self {
114 Self {
115 sheet_name: sheet_name.into(),
116 formulas,
117 }
118 }
119
120 pub fn len(&self) -> usize {
121 self.formulas.len()
122 }
123
124 pub fn is_empty(&self) -> bool {
125 self.formulas.is_empty()
126 }
127}
128
129#[derive(Debug, Clone, PartialEq, Eq)]
130pub struct FormulaIngestReport {
131 pub mode: FormulaPlaneMode,
132 pub formula_cells_seen: u64,
133 pub graph_formula_cells_materialized: u64,
134
135 pub shadow_candidate_cells: u64,
136 pub shadow_accepted_span_cells: u64,
137 pub shadow_fallback_cells: u64,
138 pub shadow_templates_interned: u64,
139 pub shadow_spans_created: u64,
140
141 pub graph_formula_vertices_avoided_shadow: u64,
142 pub ast_roots_avoided_shadow: u64,
143 pub edge_rows_avoided_shadow: u64,
144
145 pub graph_vertices_created: u64,
146 pub graph_edges_created: u64,
147
148 pub source_formula_events: u64,
149 pub source_formula_records_spooled: u64,
150 pub source_spool_encoded_bytes: u64,
151 pub source_spool_peak_memory_bytes: u64,
152 pub source_spool_spilled_bytes: u64,
153 pub source_spool_spill_files: u64,
154 pub source_spool_replays: u64,
155 pub source_ordinary_events: u64,
156 pub source_shared_anchor_events: u64,
157 pub source_shared_descendant_events: u64,
158 pub source_unknown_events: u64,
159 pub source_families_seen: u64,
160 pub source_family_cells_seen: u64,
161 pub source_family_shadow_eligible: u64,
162 pub source_family_shadow_eligible_cells: u64,
163 pub source_family_promoted: u64,
164 pub source_family_promoted_cells: u64,
165 pub source_family_fallback: u64,
166 pub source_family_fallback_cells: u64,
167 pub source_forward_descendants: u64,
168 pub source_evidence_limit_fallbacks: u64,
169 pub source_evidence_peak_bytes: u64,
170 pub source_anchor_parses: u64,
171 pub source_anchor_asts: u64,
172 pub source_anchor_analyses: u64,
173 pub source_descendant_strings_avoided: u64,
174 pub source_descendant_events_avoided: u64,
175 pub source_descendant_analyses_avoided: u64,
176 pub source_compressed_families_prepared: u64,
177 pub source_compressed_cells_prepared: u64,
178 pub source_partitioned_families_seen: u64,
179 pub source_partitioned_families_prepared: u64,
180 pub source_partitioned_families_rejected: u64,
181 pub source_partition_fragments_prepared: u64,
182 pub source_partition_span_cells_prepared: u64,
183 pub source_partition_fallback_cells: u64,
184 pub source_partition_analyses_reused: u64,
185 pub source_partition_function_semantics: u64,
186 pub source_partition_holes: u64,
187 pub source_partition_ordinary_exceptions: u64,
188 pub source_partition_failures: u64,
189 pub source_partition_surviving_cells: u64,
190
191 pub fallback_reasons: BTreeMap<String, u64>,
192}
193
194impl Default for FormulaIngestReport {
195 fn default() -> Self {
196 Self {
197 mode: FormulaPlaneMode::Off,
198 formula_cells_seen: 0,
199 graph_formula_cells_materialized: 0,
200 shadow_candidate_cells: 0,
201 shadow_accepted_span_cells: 0,
202 shadow_fallback_cells: 0,
203 shadow_templates_interned: 0,
204 shadow_spans_created: 0,
205 graph_formula_vertices_avoided_shadow: 0,
206 ast_roots_avoided_shadow: 0,
207 edge_rows_avoided_shadow: 0,
208 graph_vertices_created: 0,
209 graph_edges_created: 0,
210 source_formula_events: 0,
211 source_formula_records_spooled: 0,
212 source_spool_encoded_bytes: 0,
213 source_spool_peak_memory_bytes: 0,
214 source_spool_spilled_bytes: 0,
215 source_spool_spill_files: 0,
216 source_spool_replays: 0,
217 source_ordinary_events: 0,
218 source_shared_anchor_events: 0,
219 source_shared_descendant_events: 0,
220 source_unknown_events: 0,
221 source_families_seen: 0,
222 source_family_cells_seen: 0,
223 source_family_shadow_eligible: 0,
224 source_family_shadow_eligible_cells: 0,
225 source_family_promoted: 0,
226 source_family_promoted_cells: 0,
227 source_family_fallback: 0,
228 source_family_fallback_cells: 0,
229 source_forward_descendants: 0,
230 source_evidence_limit_fallbacks: 0,
231 source_evidence_peak_bytes: 0,
232 source_anchor_parses: 0,
233 source_anchor_asts: 0,
234 source_anchor_analyses: 0,
235 source_descendant_strings_avoided: 0,
236 source_descendant_events_avoided: 0,
237 source_descendant_analyses_avoided: 0,
238 source_compressed_families_prepared: 0,
239 source_compressed_cells_prepared: 0,
240 source_partitioned_families_seen: 0,
241 source_partitioned_families_prepared: 0,
242 source_partitioned_families_rejected: 0,
243 source_partition_fragments_prepared: 0,
244 source_partition_span_cells_prepared: 0,
245 source_partition_fallback_cells: 0,
246 source_partition_analyses_reused: 0,
247 source_partition_function_semantics: 0,
248 source_partition_holes: 0,
249 source_partition_ordinary_exceptions: 0,
250 source_partition_failures: 0,
251 source_partition_surviving_cells: 0,
252 fallback_reasons: BTreeMap::new(),
253 }
254 }
255}
256
257impl FormulaIngestReport {
258 pub(crate) fn with_mode(mode: FormulaPlaneMode) -> Self {
259 Self {
260 mode,
261 ..Self::default()
262 }
263 }
264
265 pub(crate) fn accumulate(&mut self, other: &Self) {
266 self.formula_cells_seen = self
267 .formula_cells_seen
268 .saturating_add(other.formula_cells_seen);
269 self.graph_formula_cells_materialized = self
270 .graph_formula_cells_materialized
271 .saturating_add(other.graph_formula_cells_materialized);
272 self.shadow_candidate_cells = self
273 .shadow_candidate_cells
274 .saturating_add(other.shadow_candidate_cells);
275 self.shadow_accepted_span_cells = self
276 .shadow_accepted_span_cells
277 .saturating_add(other.shadow_accepted_span_cells);
278 self.shadow_fallback_cells = self
279 .shadow_fallback_cells
280 .saturating_add(other.shadow_fallback_cells);
281 self.shadow_templates_interned = self
282 .shadow_templates_interned
283 .saturating_add(other.shadow_templates_interned);
284 self.shadow_spans_created = self
285 .shadow_spans_created
286 .saturating_add(other.shadow_spans_created);
287 self.graph_formula_vertices_avoided_shadow = self
288 .graph_formula_vertices_avoided_shadow
289 .saturating_add(other.graph_formula_vertices_avoided_shadow);
290 self.ast_roots_avoided_shadow = self
291 .ast_roots_avoided_shadow
292 .saturating_add(other.ast_roots_avoided_shadow);
293 self.edge_rows_avoided_shadow = self
294 .edge_rows_avoided_shadow
295 .saturating_add(other.edge_rows_avoided_shadow);
296 self.graph_vertices_created = self
297 .graph_vertices_created
298 .saturating_add(other.graph_vertices_created);
299 self.graph_edges_created = self
300 .graph_edges_created
301 .saturating_add(other.graph_edges_created);
302 self.source_formula_events = self
303 .source_formula_events
304 .saturating_add(other.source_formula_events);
305 self.source_formula_records_spooled = self
306 .source_formula_records_spooled
307 .saturating_add(other.source_formula_records_spooled);
308 self.source_spool_encoded_bytes = self
309 .source_spool_encoded_bytes
310 .saturating_add(other.source_spool_encoded_bytes);
311 self.source_spool_peak_memory_bytes = self
312 .source_spool_peak_memory_bytes
313 .max(other.source_spool_peak_memory_bytes);
314 self.source_spool_spilled_bytes = self
315 .source_spool_spilled_bytes
316 .saturating_add(other.source_spool_spilled_bytes);
317 self.source_spool_spill_files = self
318 .source_spool_spill_files
319 .saturating_add(other.source_spool_spill_files);
320 self.source_spool_replays = self
321 .source_spool_replays
322 .saturating_add(other.source_spool_replays);
323 self.source_ordinary_events = self
324 .source_ordinary_events
325 .saturating_add(other.source_ordinary_events);
326 self.source_shared_anchor_events = self
327 .source_shared_anchor_events
328 .saturating_add(other.source_shared_anchor_events);
329 self.source_shared_descendant_events = self
330 .source_shared_descendant_events
331 .saturating_add(other.source_shared_descendant_events);
332 self.source_unknown_events = self
333 .source_unknown_events
334 .saturating_add(other.source_unknown_events);
335 self.source_families_seen = self
336 .source_families_seen
337 .saturating_add(other.source_families_seen);
338 self.source_family_cells_seen = self
339 .source_family_cells_seen
340 .saturating_add(other.source_family_cells_seen);
341 self.source_family_shadow_eligible = self
342 .source_family_shadow_eligible
343 .saturating_add(other.source_family_shadow_eligible);
344 self.source_family_shadow_eligible_cells = self
345 .source_family_shadow_eligible_cells
346 .saturating_add(other.source_family_shadow_eligible_cells);
347 self.source_family_promoted = self
348 .source_family_promoted
349 .saturating_add(other.source_family_promoted);
350 self.source_family_promoted_cells = self
351 .source_family_promoted_cells
352 .saturating_add(other.source_family_promoted_cells);
353 self.source_family_fallback = self
354 .source_family_fallback
355 .saturating_add(other.source_family_fallback);
356 self.source_family_fallback_cells = self
357 .source_family_fallback_cells
358 .saturating_add(other.source_family_fallback_cells);
359 self.source_forward_descendants = self
360 .source_forward_descendants
361 .saturating_add(other.source_forward_descendants);
362 self.source_evidence_limit_fallbacks = self
363 .source_evidence_limit_fallbacks
364 .saturating_add(other.source_evidence_limit_fallbacks);
365 self.source_evidence_peak_bytes = self
366 .source_evidence_peak_bytes
367 .max(other.source_evidence_peak_bytes);
368 self.source_anchor_parses = self
369 .source_anchor_parses
370 .saturating_add(other.source_anchor_parses);
371 self.source_anchor_asts = self
372 .source_anchor_asts
373 .saturating_add(other.source_anchor_asts);
374 self.source_anchor_analyses = self
375 .source_anchor_analyses
376 .saturating_add(other.source_anchor_analyses);
377 self.source_descendant_strings_avoided = self
378 .source_descendant_strings_avoided
379 .saturating_add(other.source_descendant_strings_avoided);
380 self.source_descendant_events_avoided = self
381 .source_descendant_events_avoided
382 .saturating_add(other.source_descendant_events_avoided);
383 self.source_descendant_analyses_avoided = self
384 .source_descendant_analyses_avoided
385 .saturating_add(other.source_descendant_analyses_avoided);
386 self.source_compressed_families_prepared = self
387 .source_compressed_families_prepared
388 .saturating_add(other.source_compressed_families_prepared);
389 self.source_compressed_cells_prepared = self
390 .source_compressed_cells_prepared
391 .saturating_add(other.source_compressed_cells_prepared);
392 self.source_partitioned_families_seen = self
393 .source_partitioned_families_seen
394 .saturating_add(other.source_partitioned_families_seen);
395 self.source_partitioned_families_prepared = self
396 .source_partitioned_families_prepared
397 .saturating_add(other.source_partitioned_families_prepared);
398 self.source_partitioned_families_rejected = self
399 .source_partitioned_families_rejected
400 .saturating_add(other.source_partitioned_families_rejected);
401 self.source_partition_fragments_prepared = self
402 .source_partition_fragments_prepared
403 .saturating_add(other.source_partition_fragments_prepared);
404 self.source_partition_span_cells_prepared = self
405 .source_partition_span_cells_prepared
406 .saturating_add(other.source_partition_span_cells_prepared);
407 self.source_partition_fallback_cells = self
408 .source_partition_fallback_cells
409 .saturating_add(other.source_partition_fallback_cells);
410 self.source_partition_analyses_reused = self
411 .source_partition_analyses_reused
412 .saturating_add(other.source_partition_analyses_reused);
413 self.source_partition_function_semantics = self
414 .source_partition_function_semantics
415 .saturating_add(other.source_partition_function_semantics);
416 self.source_partition_holes = self
417 .source_partition_holes
418 .saturating_add(other.source_partition_holes);
419 self.source_partition_ordinary_exceptions = self
420 .source_partition_ordinary_exceptions
421 .saturating_add(other.source_partition_ordinary_exceptions);
422 self.source_partition_failures = self
423 .source_partition_failures
424 .saturating_add(other.source_partition_failures);
425 self.source_partition_surviving_cells = self
426 .source_partition_surviving_cells
427 .saturating_add(other.source_partition_surviving_cells);
428 for (reason, count) in &other.fallback_reasons {
429 let total = self.fallback_reasons.entry(reason.clone()).or_default();
430 *total = total.saturating_add(*count);
431 }
432 }
433}