1use crate::SheetId;
9use crate::engine::addr::GridAddr;
10use crate::engine::named_range::{NameScope, NamedDefinition};
11use crate::engine::row_visibility::RowVisibilitySource;
12use crate::engine::vertex::VertexId;
13use crate::reference::CellRef;
14use formualizer_common::LiteralValue;
15use formualizer_parse::parser::ASTNode;
16
17#[derive(Debug, Clone, PartialEq)]
18pub struct SpillSnapshot {
19 pub target_cells: Vec<CellRef>,
21 pub values: Vec<Vec<LiteralValue>>,
23}
24
25#[derive(Debug, Clone, PartialEq, Eq, Default)]
30pub struct ChangeEventMeta {
31 pub actor_id: Option<String>,
32 pub correlation_id: Option<String>,
33 pub reason: Option<String>,
34}
35
36#[derive(Debug, Clone, PartialEq)]
38pub enum ChangeEvent {
39 SetValue {
41 addr: CellRef,
42 old_value: Option<LiteralValue>,
43 old_formula: Option<ASTNode>,
44 new: LiteralValue,
45 },
46 SetFormula {
47 addr: CellRef,
48 old_value: Option<LiteralValue>,
49 old_formula: Option<ASTNode>,
50 new: ASTNode,
51 },
52 SetRowVisibility {
53 sheet_id: SheetId,
54 row0: u32,
55 source: RowVisibilitySource,
56 old_hidden: bool,
57 new_hidden: bool,
58 },
59 AddVertex {
61 id: VertexId,
62 coord: GridAddr,
63 sheet_id: SheetId,
64 value: Option<LiteralValue>,
65 formula: Option<ASTNode>,
66 kind: Option<crate::engine::vertex::VertexKind>,
67 flags: Option<u8>,
68 },
69 RemoveVertex {
70 id: VertexId,
71 old_value: Option<LiteralValue>,
73 old_formula: Option<ASTNode>,
74 old_dependencies: Vec<VertexId>, old_dependents: Vec<VertexId>, coord: Option<GridAddr>,
77 sheet_id: Option<SheetId>,
78 kind: Option<crate::engine::vertex::VertexKind>,
79 flags: Option<u8>,
80 },
81
82 CompoundStart {
84 description: String, depth: usize,
86 },
87 CompoundEnd {
88 depth: usize,
89 },
90
91 VertexMoved {
93 id: VertexId,
94 sheet_id: SheetId,
95 old_coord: GridAddr,
96 new_coord: GridAddr,
97 },
98 FormulaAdjusted {
99 id: VertexId,
100 addr: Option<CellRef>,
102 old_ast: ASTNode,
103 new_ast: ASTNode,
104 },
105 NamedRangeAdjusted {
106 name: String,
107 scope: NameScope,
108 old_definition: NamedDefinition,
109 new_definition: NamedDefinition,
110 },
111 EdgeAdded {
112 from: VertexId,
113 to: VertexId,
114 },
115 EdgeRemoved {
116 from: VertexId,
117 to: VertexId,
118 },
119
120 DefineName {
122 name: String,
123 scope: NameScope,
124 definition: NamedDefinition,
125 },
126 UpdateName {
127 name: String,
128 scope: NameScope,
129 old_definition: NamedDefinition,
130 new_definition: NamedDefinition,
131 },
132 DeleteName {
133 name: String,
134 scope: NameScope,
135 old_definition: Option<NamedDefinition>,
136 },
137
138 SpillCommitted {
140 anchor: VertexId,
141 old: Option<SpillSnapshot>,
142 new: SpillSnapshot,
143 },
144 SpillCleared {
145 anchor: VertexId,
146 old: SpillSnapshot,
147 },
148 StagedFormulaCellChanged {
162 sheet: String,
163 row: u32,
164 col: u32,
165 old: Option<String>,
166 new: Option<String>,
167 },
168}
169
170#[derive(Debug, Default)]
172pub struct ChangeLog {
173 events: Vec<ChangeEvent>,
174 metas: Vec<ChangeEventMeta>,
175 enabled: bool,
176 max_changelog_events: Option<usize>,
178 compound_depth: usize,
180 seqs: Vec<u64>,
182 groups: Vec<Option<u64>>,
184 next_seq: u64,
185 group_stack: Vec<u64>,
187 next_group_id: u64,
188
189 current_meta: ChangeEventMeta,
190}
191
192#[derive(Debug)]
197pub(crate) struct MutationCapture {
198 events: Vec<ChangeEvent>,
199 compound_depth: usize,
200 current_meta: ChangeEventMeta,
201}
202
203impl MutationCapture {
204 pub(crate) fn new(current_meta: ChangeEventMeta) -> Self {
205 Self {
206 events: Vec::new(),
207 compound_depth: 0,
208 current_meta,
209 }
210 }
211
212 pub(crate) fn len(&self) -> usize {
213 self.events.len()
214 }
215
216 pub(crate) fn events(&self) -> &[ChangeEvent] {
217 &self.events
218 }
219
220 pub(crate) fn close_compounds(&mut self) {
221 while self.compound_depth > 0 {
222 self.end_compound();
223 }
224 }
225
226 fn push(&mut self, event: ChangeEvent) {
227 self.events.push(event);
228 }
229}
230
231impl ChangeLogger for MutationCapture {
232 fn record(&mut self, event: ChangeEvent) {
233 self.push(event);
234 }
235
236 fn set_enabled(&mut self, _: bool) {}
237
238 fn begin_compound(&mut self, description: String) {
239 self.compound_depth += 1;
240 self.push(ChangeEvent::CompoundStart {
241 description,
242 depth: self.compound_depth,
243 });
244 }
245
246 fn end_compound(&mut self) {
247 if self.compound_depth == 0 {
248 return;
249 }
250 self.push(ChangeEvent::CompoundEnd {
251 depth: self.compound_depth,
252 });
253 self.compound_depth -= 1;
254 }
255}
256
257impl ChangeLog {
258 pub fn new() -> Self {
259 Self {
260 events: Vec::new(),
261 metas: Vec::new(),
262 enabled: true,
263 max_changelog_events: None,
264 compound_depth: 0,
265 seqs: Vec::new(),
266 groups: Vec::new(),
267 next_seq: 0,
268 group_stack: Vec::new(),
269 next_group_id: 1,
270 current_meta: ChangeEventMeta::default(),
271 }
272 }
273
274 pub fn with_max_changelog_events(max: usize) -> Self {
275 let mut out = Self::new();
276 out.max_changelog_events = Some(max);
277 out
278 }
279
280 pub fn set_max_changelog_events(&mut self, max: Option<usize>) {
281 self.max_changelog_events = max;
282 self.enforce_cap();
283 }
284
285 fn enforce_cap(&mut self) {
286 let Some(max) = self.max_changelog_events else {
287 return;
288 };
289 if max == 0 {
290 self.clear_retained();
291 return;
292 }
293 if self.events.len() <= max {
294 return;
295 }
296 let drop_n = self.events.len() - max;
297 self.events.drain(0..drop_n);
298 self.metas.drain(0..drop_n);
299 self.seqs.drain(0..drop_n);
300 self.groups.drain(0..drop_n);
301 }
302
303 fn clear_retained(&mut self) {
304 self.events.clear();
305 self.metas.clear();
306 self.seqs.clear();
307 self.groups.clear();
308 }
309
310 fn replay_record(&mut self, event: ChangeEvent, meta: &ChangeEventMeta, retain: bool) {
311 if !self.enabled {
312 return;
313 }
314 let seq = self.next_seq;
315 self.next_seq += 1;
316 if retain {
317 self.events.push(event);
318 self.metas.push(meta.clone());
319 self.seqs.push(seq);
320 self.groups.push(self.group_stack.last().copied());
321 }
322 }
323
324 fn replay_begin_compound(&mut self, description: String, meta: &ChangeEventMeta, retain: bool) {
325 self.compound_depth += 1;
326 if self.compound_depth == 1 {
327 let gid = self.next_group_id;
328 self.next_group_id += 1;
329 self.group_stack.push(gid);
330 } else if let Some(&gid) = self.group_stack.last() {
331 self.group_stack.push(gid);
332 }
333 self.replay_record(
334 ChangeEvent::CompoundStart {
335 description,
336 depth: self.compound_depth,
337 },
338 meta,
339 retain,
340 );
341 }
342
343 fn replay_end_compound(&mut self, meta: &ChangeEventMeta, retain: bool) {
344 if self.compound_depth == 0 {
345 return;
346 }
347 self.replay_record(
348 ChangeEvent::CompoundEnd {
349 depth: self.compound_depth,
350 },
351 meta,
352 retain,
353 );
354 self.compound_depth -= 1;
355 self.group_stack.pop();
356 }
357
358 fn replay_capture(&mut self, capture: MutationCapture, retain: bool) {
359 for event in capture.events {
360 match event {
361 ChangeEvent::CompoundStart { description, .. } => {
362 self.replay_begin_compound(description, &capture.current_meta, retain);
363 }
364 ChangeEvent::CompoundEnd { .. } => {
365 self.replay_end_compound(&capture.current_meta, retain);
366 }
367 event => self.replay_record(event, &capture.current_meta, retain),
368 }
369 }
370 if retain {
371 self.enforce_cap();
372 }
373 }
374
375 pub(crate) fn current_meta(&self) -> ChangeEventMeta {
376 self.current_meta.clone()
377 }
378
379 pub(crate) fn publish_capture(&mut self, capture: MutationCapture) {
380 self.replay_capture(capture, true);
381 }
382
383 pub(crate) fn discard_capture(&mut self, capture: MutationCapture) {
384 self.replay_capture(capture, false);
385 }
386
387 pub fn record(&mut self, event: ChangeEvent) {
388 if self.enabled {
389 let seq = self.next_seq;
390 self.next_seq += 1;
391 let current_group = self.group_stack.last().copied();
392 self.events.push(event);
393 self.metas.push(self.current_meta.clone());
394 self.seqs.push(seq);
395 self.groups.push(current_group);
396 self.enforce_cap();
397 }
398 }
399
400 pub fn record_with_meta(&mut self, event: ChangeEvent, meta: ChangeEventMeta) {
402 if self.enabled {
403 let seq = self.next_seq;
404 self.next_seq += 1;
405 let current_group = self.group_stack.last().copied();
406 self.events.push(event);
407 self.metas.push(meta);
408 self.seqs.push(seq);
409 self.groups.push(current_group);
410 self.enforce_cap();
411 }
412 }
413
414 pub fn begin_compound(&mut self, description: String) {
416 self.compound_depth += 1;
417 if self.compound_depth == 1 {
418 let gid = self.next_group_id;
420 self.next_group_id += 1;
421 self.group_stack.push(gid);
422 } else {
423 if let Some(&gid) = self.group_stack.last() {
425 self.group_stack.push(gid);
426 }
427 }
428 if self.enabled {
429 self.record(ChangeEvent::CompoundStart {
430 description,
431 depth: self.compound_depth,
432 });
433 }
434 }
435
436 pub fn end_compound(&mut self) {
438 if self.compound_depth > 0 {
439 if self.enabled {
440 self.record(ChangeEvent::CompoundEnd {
441 depth: self.compound_depth,
442 });
443 }
444 self.compound_depth -= 1;
445 self.group_stack.pop();
446 }
447 }
448
449 pub fn events(&self) -> &[ChangeEvent] {
450 &self.events
451 }
452
453 pub fn event_meta(&self, index: usize) -> Option<&ChangeEventMeta> {
454 self.metas.get(index)
455 }
456
457 pub fn set_actor_id(&mut self, actor_id: Option<String>) {
458 self.current_meta.actor_id = actor_id;
459 }
460
461 pub fn set_correlation_id(&mut self, correlation_id: Option<String>) {
462 self.current_meta.correlation_id = correlation_id;
463 }
464
465 pub fn set_reason(&mut self, reason: Option<String>) {
466 self.current_meta.reason = reason;
467 }
468
469 pub fn truncate(&mut self, len: usize) {
471 self.events.truncate(len);
472 self.metas.truncate(len);
473 self.seqs.truncate(len);
474 self.groups.truncate(len);
475 }
476
477 pub fn clear(&mut self) {
478 self.clear_retained();
479 self.compound_depth = 0;
480 self.group_stack.clear();
481 }
482
483 pub fn len(&self) -> usize {
484 self.events.len()
485 }
486
487 pub fn is_empty(&self) -> bool {
488 self.events.is_empty()
489 }
490
491 pub fn take_from(&mut self, index: usize) -> Vec<ChangeEvent> {
493 let events = self.events.split_off(index);
494 let _ = self.metas.split_off(index);
495 let _ = self.seqs.split_off(index);
496 let _ = self.groups.split_off(index);
497 events
498 }
499
500 pub fn set_enabled(&mut self, enabled: bool) {
502 self.enabled = enabled;
503 }
504
505 pub fn compound_depth(&self) -> usize {
507 self.compound_depth
508 }
509
510 pub fn meta(&self, index: usize) -> Option<(u64, Option<u64>)> {
512 self.seqs
513 .get(index)
514 .copied()
515 .zip(self.groups.get(index).copied())
516 }
517
518 pub fn last_group_indices(&self) -> Vec<usize> {
520 if let Some(&last_gid) = self.groups.iter().rev().flatten().next() {
521 let idxs: Vec<usize> = self
522 .groups
523 .iter()
524 .enumerate()
525 .filter_map(|(i, g)| if *g == Some(last_gid) { Some(i) } else { None })
526 .collect();
527 if !idxs.is_empty() {
528 return idxs;
529 }
530 }
531 self.events.len().checked_sub(1).into_iter().collect()
532 }
533}
534
535pub trait ChangeLogger {
537 fn record(&mut self, event: ChangeEvent);
538 fn set_enabled(&mut self, enabled: bool);
539 fn begin_compound(&mut self, description: String);
540 fn end_compound(&mut self);
541}
542
543impl ChangeLogger for ChangeLog {
544 fn record(&mut self, event: ChangeEvent) {
545 ChangeLog::record(self, event);
546 }
547
548 fn set_enabled(&mut self, enabled: bool) {
549 self.enabled = enabled;
550 }
551
552 fn begin_compound(&mut self, description: String) {
553 ChangeLog::begin_compound(self, description);
554 }
555
556 fn end_compound(&mut self) {
557 ChangeLog::end_compound(self);
558 }
559}
560
561pub struct NullChangeLogger;
563
564impl ChangeLogger for NullChangeLogger {
565 fn record(&mut self, _: ChangeEvent) {}
566 fn set_enabled(&mut self, _: bool) {}
567 fn begin_compound(&mut self, _: String) {}
568 fn end_compound(&mut self) {}
569}