1use crate::SheetId;
2use crate::engine::named_range::{NameScope, NamedDefinition, NamedRange};
3use crate::engine::sheet_registry::SheetRegistry;
4use formualizer_common::{ExcelError, ExcelErrorKind, LiteralValue};
5use formualizer_parse::parser::{ASTNode, ASTNodeType, ReferenceType};
6use rustc_hash::{FxHashMap, FxHashSet};
7
8#[cfg(test)]
9#[derive(Debug, Default, Clone)]
10pub struct GraphInstrumentation {
11 pub edges_added: u64,
12 pub stripe_inserts: u64,
13 pub stripe_removes: u64,
14}
15
16type ExtractDependenciesResult =
18 Result<(Vec<VertexId>, Vec<ReferenceType>, Vec<CellRef>), ExcelError>;
19
20pub mod editor;
21pub mod snapshot;
22
23use super::arena::{AstNodeId, DataStore, ValueRef};
24use super::delta_edges::CsrMutableEdges;
25use super::packed_coord::PackedCoord;
26use super::sheet_index::SheetIndex;
27use super::vertex::{VertexId, VertexKind};
28use super::vertex_store::{FIRST_NORMAL_VERTEX, VertexStore};
29use crate::engine::topo::{
30 GraphAdapter,
31 pk::{DynamicTopo, PkConfig},
32};
33use crate::reference::{CellRef, Coord};
34pub use editor::change_log::{ChangeEvent, ChangeLog};
37
38#[derive(Debug, Clone, PartialEq, Eq, Hash)]
42pub enum DependencyRef {
43 Cell(VertexId),
45 Range {
47 sheet: String,
48 start_row: u32,
49 start_col: u32,
50 end_row: u32, end_col: u32, },
53 WholeColumn { sheet: String, col: u32 },
55 WholeRow { sheet: String, row: u32 },
57}
58
59#[derive(Debug, Clone, Hash, PartialEq, Eq)]
61pub struct StripeKey {
62 pub sheet_id: SheetId,
63 pub stripe_type: StripeType,
64 pub index: u32, }
66
67#[derive(Debug, Clone, Hash, PartialEq, Eq)]
68pub enum StripeType {
69 Row,
70 Column,
71 Block, }
73
74const BLOCK_H: u32 = 256;
76const BLOCK_W: u32 = 256;
77
78pub fn block_index(row: u32, col: u32) -> u32 {
79 (row / BLOCK_H) << 16 | (col / BLOCK_W)
80}
81
82fn is_valid_excel_name(name: &str) -> bool {
84 if name.is_empty() || name.len() > 255 {
92 return false;
93 }
94
95 if is_cell_reference(name) {
97 return false;
98 }
99
100 let mut chars = name.chars();
101
102 if let Some(first) = chars.next() {
104 if !first.is_alphabetic() && first != '_' && first != '\\' {
105 return false;
106 }
107 }
108
109 for c in chars {
111 if !c.is_alphanumeric() && c != '.' && c != '_' {
112 return false;
113 }
114 }
115
116 true
117}
118
119fn is_cell_reference(s: &str) -> bool {
121 let s = s.trim_start_matches('$');
127
128 let letter_end = s.chars().position(|c| !c.is_alphabetic() && c != '$');
130
131 if let Some(pos) = letter_end {
132 let (col_part, rest) = s.split_at(pos);
133
134 if col_part.is_empty() || col_part.len() > 3 {
136 return false;
137 }
138
139 if !col_part.chars().all(|c| c.is_alphabetic()) {
141 return false;
142 }
143
144 let row_part = rest.trim_start_matches('$');
146
147 !row_part.is_empty() && row_part.chars().all(|c| c.is_ascii_digit())
149 } else {
150 false
152 }
153}
154
155#[derive(Debug, Clone)]
158pub struct OperationSummary {
159 pub affected_vertices: Vec<VertexId>,
161 pub created_placeholders: Vec<CellRef>,
163}
164
165#[derive(Debug)]
167pub struct DependencyGraph {
168 store: VertexStore,
170
171 edges: CsrMutableEdges,
173
174 data_store: DataStore,
176 vertex_values: FxHashMap<VertexId, ValueRef>,
177 vertex_formulas: FxHashMap<VertexId, AstNodeId>,
178
179 cell_to_vertex: FxHashMap<CellRef, VertexId>,
181
182 dirty_vertices: FxHashSet<VertexId>,
184 volatile_vertices: FxHashSet<VertexId>,
185
186 formula_to_range_deps: FxHashMap<VertexId, Vec<ReferenceType>>,
189
190 stripe_to_dependents: FxHashMap<StripeKey, FxHashSet<VertexId>>,
193
194 sheet_indexes: FxHashMap<SheetId, SheetIndex>,
197
198 sheet_reg: SheetRegistry,
200 default_sheet_id: SheetId,
201
202 named_ranges: FxHashMap<String, NamedRange>,
205
206 sheet_named_ranges: FxHashMap<(SheetId, String), NamedRange>,
208
209 vertex_to_names: FxHashMap<VertexId, Vec<String>>,
211
212 config: super::EvalConfig,
214
215 pk_order: Option<DynamicTopo<VertexId>>,
217
218 spill_anchor_to_cells: FxHashMap<VertexId, Vec<CellRef>>,
220 spill_cell_to_anchor: FxHashMap<CellRef, VertexId>,
221
222 first_load_assume_new: bool,
224 ensure_touched_sheets: FxHashSet<SheetId>,
225
226 #[cfg(test)]
227 instr: GraphInstrumentation,
228}
229
230impl Default for DependencyGraph {
231 fn default() -> Self {
232 Self::new()
233 }
234}
235
236impl DependencyGraph {
237 pub fn range_expansion_limit(&self) -> usize {
239 self.config.range_expansion_limit
240 }
241
242 pub fn get_config(&self) -> &super::EvalConfig {
243 &self.config
244 }
245
246 pub fn plan_dependencies<'a, I>(
248 &mut self,
249 items: I,
250 policy: &formualizer_parse::parser::CollectPolicy,
251 volatile: Option<&[bool]>,
252 ) -> Result<crate::engine::plan::DependencyPlan, formualizer_common::ExcelError>
253 where
254 I: IntoIterator<Item = (&'a str, u32, u32, &'a formualizer_parse::parser::ASTNode)>,
255 {
256 crate::engine::plan::build_dependency_plan(
257 &mut self.sheet_reg,
258 items.into_iter(),
259 policy,
260 volatile,
261 )
262 }
263
264 pub fn ensure_vertices_batch(
267 &mut self,
268 coords: &[(SheetId, PackedCoord)],
269 ) -> Vec<(PackedCoord, u32)> {
270 use rustc_hash::FxHashMap;
271 let mut grouped: FxHashMap<SheetId, Vec<PackedCoord>> = FxHashMap::default();
272 for (sid, pc) in coords.iter().copied() {
273 let addr = CellRef::new(sid, Coord::new(pc.row(), pc.col(), true, true));
274 if self.cell_to_vertex.contains_key(&addr) {
275 continue;
276 }
277 grouped.entry(sid).or_default().push(pc);
278 }
279 let mut add_batch: Vec<(PackedCoord, u32)> = Vec::new();
280 for (sid, pcs) in grouped {
281 if pcs.is_empty() {
282 continue;
283 }
284 self.ensure_touched_sheets.insert(sid);
286 let vids = self.store.allocate_contiguous(sid, &pcs, 0x00);
287 for (i, pc) in pcs.iter().enumerate() {
288 let vid = vids[i];
289 add_batch.push((*pc, vid.0));
290 let addr = CellRef::new(sid, Coord::new(pc.row(), pc.col(), true, true));
291 self.cell_to_vertex.insert(addr, vid);
292 match self.config.sheet_index_mode {
294 crate::engine::SheetIndexMode::Eager
295 | crate::engine::SheetIndexMode::FastBatch => {
296 self.sheet_index_mut(sid).add_vertex(*pc, vid);
297 }
298 crate::engine::SheetIndexMode::Lazy => {
299 }
301 }
302 }
303 }
304 if !add_batch.is_empty() {
305 self.edges.add_vertices_batch(&add_batch);
306 }
307 add_batch
308 }
309
310 pub fn set_first_load_assume_new(&mut self, enabled: bool) {
312 self.first_load_assume_new = enabled;
313 }
314
315 pub fn reset_ensure_touched(&mut self) {
317 self.ensure_touched_sheets.clear();
318 }
319
320 pub fn store_asts_batch<'a, I>(&mut self, asts: I) -> Vec<AstNodeId>
322 where
323 I: IntoIterator<Item = &'a formualizer_parse::parser::ASTNode>,
324 {
325 self.data_store.store_asts_batch(asts, &self.sheet_reg)
326 }
327
328 pub fn vid_for_sid_pc(&self, sid: SheetId, pc: PackedCoord) -> Option<VertexId> {
330 let addr = CellRef::new(sid, Coord::new(pc.row(), pc.col(), true, true));
331 self.cell_to_vertex.get(&addr).copied()
332 }
333
334 pub fn vid_for_plan_idx(
336 &self,
337 plan: &crate::engine::plan::DependencyPlan,
338 idx: u32,
339 ) -> Option<VertexId> {
340 let (sid, pc) = plan.global_cells.get(idx as usize).copied()?;
341 self.vid_for_sid_pc(sid, pc)
342 }
343
344 pub fn assign_formula_vertex(&mut self, vid: VertexId, ast_id: AstNodeId, volatile: bool) {
346 if self.vertex_formulas.contains_key(&vid) {
347 self.remove_dependent_edges(vid);
348 }
349 self.store
350 .set_kind(vid, crate::engine::vertex::VertexKind::FormulaScalar);
351 self.vertex_values.remove(&vid);
352 self.vertex_formulas.insert(vid, ast_id);
353 if volatile {
354 self.store.set_volatile(vid, true);
355 self.volatile_vertices.insert(vid);
356 }
357 self.mark_vertex_dirty(vid);
359 }
360
361 pub fn add_edges_nobatch(&mut self, dependent: VertexId, dependencies: &[VertexId]) {
363 self.add_dependent_edges_nobatch(dependent, dependencies);
364 }
365
366 pub fn add_range_edges(
368 &mut self,
369 dependent: VertexId,
370 ranges: &[ReferenceType],
371 current_sheet_id: SheetId,
372 ) {
373 self.add_range_dependent_edges(dependent, ranges, current_sheet_id);
374 }
375
376 pub fn iter_vertex_ids(&self) -> impl Iterator<Item = VertexId> + '_ {
378 self.store.all_vertices()
379 }
380
381 pub fn vertex_coord(&self, vid: VertexId) -> PackedCoord {
383 self.store.coord(vid)
384 }
385
386 pub fn vertex_count(&self) -> usize {
388 self.store.len()
389 }
390
391 pub fn build_edges_from_adjacency(
393 &mut self,
394 adjacency: Vec<(u32, Vec<u32>)>,
395 coords: Vec<PackedCoord>,
396 vertex_ids: Vec<u32>,
397 ) {
398 self.edges
399 .build_from_adjacency(adjacency, coords, vertex_ids);
400 }
401 pub fn used_row_bounds_for_columns(
403 &self,
404 sheet_id: SheetId,
405 start_col: u32,
406 end_col: u32,
407 ) -> Option<(u32, u32)> {
408 if let Some(index) = self.sheet_indexes.get(&sheet_id) {
410 if !index.is_empty() {
411 let mut min_r: Option<u32> = None;
412 let mut max_r: Option<u32> = None;
413 for vid in index.vertices_in_col_range(start_col, end_col) {
414 let r = self.store.coord(vid).row();
415 min_r = Some(min_r.map(|m| m.min(r)).unwrap_or(r));
416 max_r = Some(max_r.map(|m| m.max(r)).unwrap_or(r));
417 }
418 return match (min_r, max_r) {
419 (Some(a), Some(b)) => Some((a, b)),
420 _ => None,
421 };
422 }
423 }
424 let mut min_r: Option<u32> = None;
426 let mut max_r: Option<u32> = None;
427 for cref in self.cell_to_vertex.keys() {
428 if cref.sheet_id == sheet_id {
429 let c = cref.coord.col;
430 if c >= start_col && c <= end_col {
431 let r = cref.coord.row;
432 min_r = Some(min_r.map(|m| m.min(r)).unwrap_or(r));
433 max_r = Some(max_r.map(|m| m.max(r)).unwrap_or(r));
434 }
435 }
436 }
437 match (min_r, max_r) {
438 (Some(a), Some(b)) => Some((a, b)),
439 _ => None,
440 }
441 }
442
443 pub fn finalize_sheet_index(&mut self, sheet: &str) {
445 let Some(sheet_id) = self.sheet_reg.get_id(sheet) else {
446 return;
447 };
448 if let Some(idx) = self.sheet_indexes.get(&sheet_id) {
450 if !idx.is_empty() {
451 return;
452 }
453 }
454 let mut idx = SheetIndex::new();
455 let mut batch: Vec<(PackedCoord, VertexId)> = Vec::with_capacity(self.cell_to_vertex.len());
457 for (cref, vid) in &self.cell_to_vertex {
458 if cref.sheet_id == sheet_id {
459 batch.push((PackedCoord::new(cref.coord.row, cref.coord.col), *vid));
460 }
461 }
462 idx.add_vertices_batch(&batch);
464 self.sheet_indexes.insert(sheet_id, idx);
465 }
466
467 pub fn set_sheet_index_mode(&mut self, mode: crate::engine::SheetIndexMode) {
468 self.config.sheet_index_mode = mode;
469 }
470
471 pub fn used_col_bounds_for_rows(
473 &self,
474 sheet_id: SheetId,
475 start_row: u32,
476 end_row: u32,
477 ) -> Option<(u32, u32)> {
478 if let Some(index) = self.sheet_indexes.get(&sheet_id) {
479 if !index.is_empty() {
480 let mut min_c: Option<u32> = None;
481 let mut max_c: Option<u32> = None;
482 for vid in index.vertices_in_row_range(start_row, end_row) {
483 let c = self.store.coord(vid).col();
484 min_c = Some(min_c.map(|m| m.min(c)).unwrap_or(c));
485 max_c = Some(max_c.map(|m| m.max(c)).unwrap_or(c));
486 }
487 return match (min_c, max_c) {
488 (Some(a), Some(b)) => Some((a, b)),
489 _ => None,
490 };
491 }
492 }
493 let mut min_c: Option<u32> = None;
495 let mut max_c: Option<u32> = None;
496 for cref in self.cell_to_vertex.keys() {
497 if cref.sheet_id == sheet_id {
498 let r = cref.coord.row;
499 if r >= start_row && r <= end_row {
500 let c = cref.coord.col;
501 min_c = Some(min_c.map(|m| m.min(c)).unwrap_or(c));
502 max_c = Some(max_c.map(|m| m.max(c)).unwrap_or(c));
503 }
504 }
505 }
506 match (min_c, max_c) {
507 (Some(a), Some(b)) => Some((a, b)),
508 _ => None,
509 }
510 }
511
512 pub fn sheet_has_formulas(&self, sheet_id: SheetId) -> bool {
514 for &vid in self.vertex_formulas.keys() {
516 if self.store.sheet_id(vid) == sheet_id {
517 return true;
518 }
519 }
520 false
521 }
522 pub fn new() -> Self {
523 let mut sheet_reg = SheetRegistry::new();
524 let default_sheet_id = sheet_reg.id_for("Sheet1");
525 Self {
526 store: VertexStore::new(),
527 edges: CsrMutableEdges::new(),
528 data_store: DataStore::new(),
529 vertex_values: FxHashMap::default(),
530 vertex_formulas: FxHashMap::default(),
531 cell_to_vertex: FxHashMap::default(),
532 dirty_vertices: FxHashSet::default(),
533 volatile_vertices: FxHashSet::default(),
534 formula_to_range_deps: FxHashMap::default(),
535 stripe_to_dependents: FxHashMap::default(),
536 sheet_indexes: FxHashMap::default(),
537 sheet_reg,
538 default_sheet_id,
539 named_ranges: FxHashMap::default(),
540 sheet_named_ranges: FxHashMap::default(),
541 vertex_to_names: FxHashMap::default(),
542 config: super::EvalConfig::default(),
543 pk_order: None,
544 spill_anchor_to_cells: FxHashMap::default(),
545 spill_cell_to_anchor: FxHashMap::default(),
546 first_load_assume_new: false,
547 ensure_touched_sheets: FxHashSet::default(),
548 #[cfg(test)]
549 instr: GraphInstrumentation::default(),
550 }
551 }
552
553 pub fn new_with_config(config: super::EvalConfig) -> Self {
554 let mut g = Self {
555 config: config.clone(),
556 ..Self::new()
557 };
558 if config.use_dynamic_topo {
559 let nodes = g
561 .store
562 .all_vertices()
563 .filter(|&id| g.store.vertex_exists_active(id));
564 let mut pk = DynamicTopo::new(
565 nodes,
566 PkConfig {
567 visit_budget: config.pk_visit_budget,
568 compaction_interval_ops: config.pk_compaction_interval_ops,
569 },
570 );
571 let adapter = GraphAdapter { g: &g };
573 pk.rebuild_full(&adapter);
574 g.pk_order = Some(pk);
575 }
576 g
577 }
578
579 pub(crate) fn pk_layers_for(&self, subset: &[VertexId]) -> Option<Vec<crate::engine::Layer>> {
581 let pk = self.pk_order.as_ref()?;
582 let adapter = crate::engine::topo::GraphAdapter { g: self };
583 let layers = pk.layers_for(&adapter, subset, self.config.max_layer_width);
584 Some(
585 layers
586 .into_iter()
587 .map(|vs| crate::engine::Layer { vertices: vs })
588 .collect(),
589 )
590 }
591
592 #[inline]
593 pub(crate) fn dynamic_topo_enabled(&self) -> bool {
594 self.pk_order.is_some()
595 }
596
597 #[cfg(test)]
598 pub fn reset_instr(&mut self) {
599 self.instr = GraphInstrumentation::default();
600 }
601
602 #[cfg(test)]
603 pub fn instr(&self) -> GraphInstrumentation {
604 self.instr.clone()
605 }
606
607 pub fn begin_batch(&mut self) {
609 self.edges.begin_batch();
610 }
611
612 pub fn end_batch(&mut self) {
614 self.edges.end_batch();
615 }
616
617 pub fn default_sheet_id(&self) -> SheetId {
618 self.default_sheet_id
619 }
620
621 pub fn default_sheet_name(&self) -> &str {
622 self.sheet_reg.name(self.default_sheet_id)
623 }
624
625 pub fn set_default_sheet_by_name(&mut self, name: &str) {
626 self.default_sheet_id = self.sheet_id_mut(name);
627 }
628
629 pub fn set_default_sheet_by_id(&mut self, id: SheetId) {
630 self.default_sheet_id = id;
631 }
632
633 pub fn sheet_id_mut(&mut self, name: &str) -> SheetId {
635 self.sheet_reg.id_for(name)
636 }
637
638 pub fn sheet_id(&self, name: &str) -> Option<SheetId> {
639 self.sheet_reg.get_id(name)
640 }
641
642 fn resolve_existing_sheet_id(&self, name: &str) -> Result<SheetId, ExcelError> {
644 self.sheet_id(name).ok_or_else(|| {
645 ExcelError::new(ExcelErrorKind::Ref).with_message(format!("Sheet not found: {name}"))
646 })
647 }
648
649 pub fn sheet_name(&self, id: SheetId) -> &str {
651 self.sheet_reg.name(id)
652 }
653
654 pub fn sheet_reg(&self) -> &SheetRegistry {
656 &self.sheet_reg
657 }
658
659 pub fn to_a1(&self, cell_ref: CellRef) -> String {
661 format!("{}!{}", self.sheet_name(cell_ref.sheet_id), cell_ref.coord)
662 }
663
664 pub fn define_name(
668 &mut self,
669 name: &str,
670 definition: NamedDefinition,
671 scope: NameScope,
672 ) -> Result<(), ExcelError> {
673 if !is_valid_excel_name(name) {
675 return Err(
676 ExcelError::new(ExcelErrorKind::Name).with_message(format!("Invalid name: {name}"))
677 );
678 }
679
680 match scope {
682 NameScope::Workbook => {
683 if self.named_ranges.contains_key(name) {
684 return Err(ExcelError::new(ExcelErrorKind::Name)
685 .with_message(format!("Name already exists: {name}")));
686 }
687 }
688 NameScope::Sheet(sheet_id) => {
689 if self
690 .sheet_named_ranges
691 .contains_key(&(sheet_id, name.to_string()))
692 {
693 return Err(ExcelError::new(ExcelErrorKind::Name)
694 .with_message(format!("Name already exists in sheet: {name}")));
695 }
696 }
697 }
698
699 let named_range = match definition {
701 NamedDefinition::Formula { ref ast, .. } => {
702 let (deps, range_deps, _) = self.extract_dependencies(
703 ast,
704 match scope {
705 NameScope::Sheet(id) => id,
706 NameScope::Workbook => self.default_sheet_id,
707 },
708 )?;
709 NamedRange {
710 definition: NamedDefinition::Formula {
711 ast: ast.clone(),
712 dependencies: deps,
713 range_deps,
714 },
715 scope,
716 dependents: FxHashSet::default(),
717 }
718 }
719 _ => NamedRange {
720 definition,
721 scope,
722 dependents: FxHashSet::default(),
723 },
724 };
725
726 match scope {
728 NameScope::Workbook => {
729 self.named_ranges.insert(name.to_string(), named_range);
730 }
731 NameScope::Sheet(id) => {
732 self.sheet_named_ranges
733 .insert((id, name.to_string()), named_range);
734 }
735 }
736
737 Ok(())
738 }
739
740 pub fn named_ranges_iter(&self) -> impl Iterator<Item = (&String, &NamedRange)> {
742 self.named_ranges.iter()
743 }
744
745 pub fn sheet_named_ranges_iter(
747 &self,
748 ) -> impl Iterator<Item = (&(SheetId, String), &NamedRange)> {
749 self.sheet_named_ranges.iter()
750 }
751
752 pub fn resolve_name(&self, name: &str, current_sheet: SheetId) -> Option<&NamedDefinition> {
754 self.sheet_named_ranges
756 .get(&(current_sheet, name.to_string()))
757 .or_else(|| self.named_ranges.get(name))
758 .map(|nr| &nr.definition)
759 }
760
761 pub fn update_name(
763 &mut self,
764 name: &str,
765 new_definition: NamedDefinition,
766 scope: NameScope,
767 ) -> Result<(), ExcelError> {
768 let dependents_to_dirty = match scope {
770 NameScope::Workbook => self
771 .named_ranges
772 .get(name)
773 .map(|nr| nr.dependents.iter().copied().collect::<Vec<_>>()),
774 NameScope::Sheet(id) => self
775 .sheet_named_ranges
776 .get(&(id, name.to_string()))
777 .map(|nr| nr.dependents.iter().copied().collect::<Vec<_>>()),
778 };
779
780 if let Some(dependents) = dependents_to_dirty {
781 for vertex_id in dependents {
783 self.mark_vertex_dirty(vertex_id);
784 }
785
786 let named_range = match scope {
788 NameScope::Workbook => self.named_ranges.get_mut(name),
789 NameScope::Sheet(id) => self.sheet_named_ranges.get_mut(&(id, name.to_string())),
790 };
791
792 if let Some(named_range) = named_range {
793 named_range.definition = new_definition;
795
796 named_range.dependents.clear();
798 }
799
800 Ok(())
801 } else {
802 Err(ExcelError::new(ExcelErrorKind::Name)
803 .with_message(format!("Name not found: {name}")))
804 }
805 }
806
807 pub fn delete_name(&mut self, name: &str, scope: NameScope) -> Result<(), ExcelError> {
809 let named_range = match scope {
810 NameScope::Workbook => self.named_ranges.remove(name),
811 NameScope::Sheet(id) => self.sheet_named_ranges.remove(&(id, name.to_string())),
812 };
813
814 if let Some(named_range) = named_range {
815 for &vertex_id in &named_range.dependents {
817 self.mark_vertex_dirty(vertex_id);
819 if let Some(names) = self.vertex_to_names.get_mut(&vertex_id) {
821 names.retain(|n| n != name);
822 }
823 }
824 Ok(())
825 } else {
826 Err(ExcelError::new(ExcelErrorKind::Name)
827 .with_message(format!("Name not found: {name}")))
828 }
829 }
830
831 #[cfg(test)]
832 pub(crate) fn formula_to_range_deps(&self) -> &FxHashMap<VertexId, Vec<ReferenceType>> {
833 &self.formula_to_range_deps
834 }
835
836 #[cfg(test)]
837 pub(crate) fn stripe_to_dependents(&self) -> &FxHashMap<StripeKey, FxHashSet<VertexId>> {
838 &self.stripe_to_dependents
839 }
840
841 pub(crate) fn vertex_len(&self) -> usize {
842 self.store.len()
843 }
844
845 pub fn get_range_dependencies(
849 &self,
850 vertex: VertexId,
851 ) -> Option<&Vec<formualizer_parse::parser::ReferenceType>> {
852 self.formula_to_range_deps.get(&vertex)
853 }
854
855 pub fn sheet_index_mut(&mut self, sheet_id: SheetId) -> &mut SheetIndex {
858 self.sheet_indexes.entry(sheet_id).or_default()
859 }
860
861 pub fn sheet_index(&self, sheet_id: SheetId) -> Option<&SheetIndex> {
863 self.sheet_indexes.get(&sheet_id)
864 }
865
866 pub fn set_cell_value(
868 &mut self,
869 sheet: &str,
870 row: u32,
871 col: u32,
872 value: LiteralValue,
873 ) -> Result<OperationSummary, ExcelError> {
874 let sheet_id = self.sheet_id_mut(sheet);
875 let coord = Coord::new(row, col, true, true); let addr = CellRef::new(sheet_id, coord);
877 let mut created_placeholders = Vec::new();
878
879 let vertex_id = if let Some(&existing_id) = self.cell_to_vertex.get(&addr) {
880 let is_formula = matches!(
882 self.store.kind(existing_id),
883 VertexKind::FormulaScalar | VertexKind::FormulaArray
884 );
885
886 if is_formula {
887 self.remove_dependent_edges(existing_id);
888 self.vertex_formulas.remove(&existing_id);
889 }
890
891 self.store.set_kind(existing_id, VertexKind::Cell);
893 let value_ref = self.data_store.store_value(value);
894 self.vertex_values.insert(existing_id, value_ref);
895 existing_id
896 } else {
897 created_placeholders.push(addr);
899 let packed_coord = PackedCoord::new(row, col);
900 let vertex_id = self.store.allocate(packed_coord, sheet_id, 0x01); self.edges.add_vertex(packed_coord, vertex_id.0);
904
905 self.sheet_index_mut(sheet_id)
907 .add_vertex(packed_coord, vertex_id);
908
909 self.store.set_kind(vertex_id, VertexKind::Cell);
910 let value_ref = self.data_store.store_value(value);
911 self.vertex_values.insert(vertex_id, value_ref);
912 self.cell_to_vertex.insert(addr, vertex_id);
913 vertex_id
914 };
915
916 Ok(OperationSummary {
917 affected_vertices: self.mark_dirty(vertex_id),
918 created_placeholders,
919 })
920 }
921
922 pub fn reserve_cells(&mut self, additional: usize) {
924 self.store.reserve(additional);
925 self.vertex_values.reserve(additional);
926 self.cell_to_vertex.reserve(additional);
927 }
929
930 pub fn set_cell_value_bulk_untracked(
932 &mut self,
933 sheet: &str,
934 row: u32,
935 col: u32,
936 value: LiteralValue,
937 ) {
938 let sheet_id = self.sheet_id_mut(sheet);
939 let coord = Coord::new(row, col, true, true);
940 let addr = CellRef::new(sheet_id, coord);
941 if let Some(&existing_id) = self.cell_to_vertex.get(&addr) {
942 let value_ref = self.data_store.store_value(value);
944 self.vertex_values.insert(existing_id, value_ref);
945 self.store.set_kind(existing_id, VertexKind::Cell);
946 return;
947 }
948 let packed_coord = PackedCoord::new(row, col);
949 let vertex_id = self.store.allocate(packed_coord, sheet_id, 0x00); self.edges.add_vertex(packed_coord, vertex_id.0);
951 self.sheet_index_mut(sheet_id)
952 .add_vertex(packed_coord, vertex_id);
953 self.store.set_kind(vertex_id, VertexKind::Cell);
954 let value_ref = self.data_store.store_value(value);
955 self.vertex_values.insert(vertex_id, value_ref);
956 self.cell_to_vertex.insert(addr, vertex_id);
957 }
958
959 pub fn bulk_insert_values<I>(&mut self, sheet: &str, cells: I)
961 where
962 I: IntoIterator<Item = (u32, u32, LiteralValue)>,
963 {
964 use std::time::Instant;
965 let t0 = Instant::now();
966 let collected: Vec<(u32, u32, LiteralValue)> = cells.into_iter().collect();
968 if collected.is_empty() {
969 return;
970 }
971 let sheet_id = self.sheet_id_mut(sheet);
972 self.reserve_cells(collected.len());
973 let t_reserve = Instant::now();
974 let mut new_vertices: Vec<(PackedCoord, u32)> = Vec::with_capacity(collected.len());
975 let mut index_items: Vec<(PackedCoord, VertexId)> = Vec::with_capacity(collected.len());
976 let mut new_value_coords: Vec<(PackedCoord, VertexId)> =
978 Vec::with_capacity(collected.len());
979 let mut new_value_literals: Vec<LiteralValue> = Vec::with_capacity(collected.len());
980 let assume_new = self.first_load_assume_new
982 && self
983 .sheet_id(sheet)
984 .map(|sid| !self.ensure_touched_sheets.contains(&sid))
985 .unwrap_or(false);
986
987 for (row, col, value) in collected {
988 let coord = Coord::new(row, col, true, true);
989 let addr = CellRef::new(sheet_id, coord);
990 if !assume_new {
991 if let Some(&existing_id) = self.cell_to_vertex.get(&addr) {
992 let value_ref = self.data_store.store_value(value);
993 self.vertex_values.insert(existing_id, value_ref);
994 self.store.set_kind(existing_id, VertexKind::Cell);
995 continue;
996 }
997 }
998 let packed = PackedCoord::new(row, col);
999 let vertex_id = self.store.allocate(packed, sheet_id, 0x00);
1000 self.store.set_kind(vertex_id, VertexKind::Cell);
1001 new_value_coords.push((packed, vertex_id));
1003 new_value_literals.push(value);
1004 self.cell_to_vertex.insert(addr, vertex_id);
1005 new_vertices.push((packed, vertex_id.0));
1006 index_items.push((packed, vertex_id));
1007 }
1008 if !new_value_literals.is_empty() {
1010 let vrefs = self.data_store.store_values_batch(new_value_literals);
1011 debug_assert_eq!(vrefs.len(), new_value_coords.len());
1012 for (i, (_pc, vid)) in new_value_coords.iter().enumerate() {
1013 self.vertex_values.insert(*vid, vrefs[i]);
1014 }
1015 }
1016 let t_after_alloc = Instant::now();
1017 if !new_vertices.is_empty() {
1018 let t_edges_start = Instant::now();
1019 self.edges.add_vertices_batch(&new_vertices);
1020 let t_edges_done = Instant::now();
1021
1022 match self.config.sheet_index_mode {
1023 crate::engine::SheetIndexMode::Eager => {
1024 self.sheet_index_mut(sheet_id)
1025 .add_vertices_batch(&index_items);
1026 }
1027 crate::engine::SheetIndexMode::Lazy => {
1028 }
1030 crate::engine::SheetIndexMode::FastBatch => {
1031 self.sheet_index_mut(sheet_id)
1033 .add_vertices_batch(&index_items);
1034 }
1035 }
1036 let t_index_done = Instant::now();
1037 }
1038 }
1039
1040 pub fn set_cell_formula(
1042 &mut self,
1043 sheet: &str,
1044 row: u32,
1045 col: u32,
1046 ast: ASTNode,
1047 ) -> Result<OperationSummary, ExcelError> {
1048 let volatile = self.is_ast_volatile(&ast);
1049 self.set_cell_formula_with_volatility(sheet, row, col, ast, volatile)
1050 }
1051
1052 pub fn set_cell_formula_with_volatility(
1054 &mut self,
1055 sheet: &str,
1056 row: u32,
1057 col: u32,
1058 ast: ASTNode,
1059 volatile: bool,
1060 ) -> Result<OperationSummary, ExcelError> {
1061 let dbg = std::env::var("FZ_DEBUG_LOAD")
1062 .ok()
1063 .is_some_and(|v| v != "0");
1064 let dep_ms_thresh: u128 = std::env::var("FZ_DEBUG_DEP_MS")
1065 .ok()
1066 .and_then(|s| s.parse().ok())
1067 .unwrap_or(0);
1068 let sample_n: usize = std::env::var("FZ_DEBUG_SAMPLE_N")
1069 .ok()
1070 .and_then(|s| s.parse().ok())
1071 .unwrap_or(0);
1072 let t0 = if dbg {
1073 Some(std::time::Instant::now())
1074 } else {
1075 None
1076 };
1077 let sheet_id = self.sheet_id_mut(sheet);
1078 let coord = Coord::new(row, col, true, true);
1079 let addr = CellRef::new(sheet_id, coord);
1080
1081 let t_dep0 = if dbg {
1083 Some(std::time::Instant::now())
1084 } else {
1085 None
1086 };
1087 let (new_dependencies, new_range_dependencies, mut created_placeholders) =
1088 self.extract_dependencies(&ast, sheet_id)?;
1089 if let (true, Some(t)) = (dbg, t_dep0) {
1090 let elapsed = t.elapsed().as_millis();
1091 let do_log = (dep_ms_thresh > 0 && elapsed >= dep_ms_thresh)
1093 || (sample_n > 0 && (row as usize % sample_n == 0));
1094 if dep_ms_thresh == 0 && sample_n == 0 {
1095 if (row % 1000) == 0 {
1097 eprintln!(
1098 "[fz][dep] {}!{} extracted: deps={}, ranges={}, placeholders={} in {} ms",
1099 self.sheet_name(sheet_id),
1100 crate::reference::Coord::new(row, col, true, true),
1101 new_dependencies.len(),
1102 new_range_dependencies.len(),
1103 created_placeholders.len(),
1104 elapsed
1105 );
1106 }
1107 } else if do_log {
1108 eprintln!(
1109 "[fz][dep] {}!{} extracted: deps={}, ranges={}, placeholders={} in {} ms",
1110 self.sheet_name(sheet_id),
1111 crate::reference::Coord::new(row, col, true, true),
1112 new_dependencies.len(),
1113 new_range_dependencies.len(),
1114 created_placeholders.len(),
1115 elapsed
1116 );
1117 }
1118 }
1119
1120 let addr_vertex_id = self.get_or_create_vertex(&addr, &mut created_placeholders);
1122
1123 if new_dependencies.contains(&addr_vertex_id) {
1124 return Err(ExcelError::new(ExcelErrorKind::Circ)
1125 .with_message("Self-reference detected".to_string()));
1126 }
1127
1128 self.remove_dependent_edges(addr_vertex_id);
1130
1131 self.store
1133 .set_kind(addr_vertex_id, VertexKind::FormulaScalar);
1134 let ast_id = self.data_store.store_ast(&ast, &self.sheet_reg);
1135 self.vertex_formulas.insert(addr_vertex_id, ast_id);
1136 self.store.set_dirty(addr_vertex_id, true);
1137
1138 self.vertex_values.remove(&addr_vertex_id);
1140
1141 if volatile {
1142 self.store.set_volatile(addr_vertex_id, true);
1143 }
1144
1145 if let (true, Some(t)) = (dbg, t0) {
1146 let elapsed = t.elapsed().as_millis();
1147 let log_set = dep_ms_thresh > 0 && elapsed >= dep_ms_thresh;
1148 if log_set {
1149 eprintln!(
1150 "[fz][set] {}!{} total {} ms",
1151 self.sheet_name(sheet_id),
1152 crate::reference::Coord::new(row, col, true, true),
1153 elapsed
1154 );
1155 }
1156 }
1157
1158 self.add_dependent_edges(addr_vertex_id, &new_dependencies);
1160 self.add_range_dependent_edges(addr_vertex_id, &new_range_dependencies, sheet_id);
1161
1162 if volatile {
1164 self.volatile_vertices.insert(addr_vertex_id);
1165 }
1166
1167 Ok(OperationSummary {
1168 affected_vertices: self.mark_dirty(addr_vertex_id),
1169 created_placeholders,
1170 })
1171 }
1172
1173 pub fn get_cell_value(&self, sheet: &str, row: u32, col: u32) -> Option<LiteralValue> {
1175 let sheet_id = self.sheet_reg.get_id(sheet)?;
1176 let coord = Coord::new(row, col, true, true);
1177 let addr = CellRef::new(sheet_id, coord);
1178
1179 self.cell_to_vertex.get(&addr).and_then(|&vertex_id| {
1180 self.vertex_values
1182 .get(&vertex_id)
1183 .map(|&value_ref| self.data_store.retrieve_value(value_ref))
1184 })
1185 }
1186
1187 fn mark_dirty(&mut self, vertex_id: VertexId) -> Vec<VertexId> {
1189 let mut affected = FxHashSet::default();
1190 let mut to_visit = Vec::new();
1191 let mut visited_for_propagation = FxHashSet::default();
1192
1193 let is_formula = matches!(
1196 self.store.kind(vertex_id),
1197 VertexKind::FormulaScalar | VertexKind::FormulaArray
1198 );
1199
1200 if is_formula {
1201 to_visit.push(vertex_id);
1202 } else {
1203 affected.insert(vertex_id);
1205 }
1206
1207 {
1209 let dependents = self.get_dependents(vertex_id);
1211 to_visit.extend(&dependents);
1212
1213 let view = self.store.view(vertex_id);
1215 let row = view.row();
1216 let col = view.col();
1217 let dirty_sheet_id = view.sheet_id();
1218
1219 let mut potential_dependents = FxHashSet::default();
1221
1222 let column_key = StripeKey {
1224 sheet_id: dirty_sheet_id,
1225 stripe_type: StripeType::Column,
1226 index: col,
1227 };
1228 if let Some(dependents) = self.stripe_to_dependents.get(&column_key) {
1229 potential_dependents.extend(dependents);
1230 }
1231
1232 let row_key = StripeKey {
1234 sheet_id: dirty_sheet_id,
1235 stripe_type: StripeType::Row,
1236 index: row,
1237 };
1238 if let Some(dependents) = self.stripe_to_dependents.get(&row_key) {
1239 potential_dependents.extend(dependents);
1240 }
1241
1242 if self.config.enable_block_stripes {
1244 let block_key = StripeKey {
1245 sheet_id: dirty_sheet_id,
1246 stripe_type: StripeType::Block,
1247 index: block_index(row, col),
1248 };
1249 if let Some(dependents) = self.stripe_to_dependents.get(&block_key) {
1250 potential_dependents.extend(dependents);
1251 }
1252 }
1253
1254 for &dep_id in &potential_dependents {
1256 if let Some(ranges) = self.formula_to_range_deps.get(&dep_id) {
1257 for range in ranges {
1258 if let ReferenceType::Range {
1259 sheet,
1260 start_row,
1261 start_col,
1262 end_row,
1263 end_col,
1264 } = range
1265 {
1266 let range_sheet_name = sheet
1267 .as_deref()
1268 .unwrap_or_else(|| self.sheet_name(dirty_sheet_id));
1269 if let Some(range_sheet_id) = self.sheet_reg.get_id(range_sheet_name) {
1270 if range_sheet_id == dirty_sheet_id
1271 && row >= start_row.unwrap_or(1)
1272 && row <= end_row.unwrap_or(u32::MAX)
1273 && col >= start_col.unwrap_or(1)
1274 && col <= end_col.unwrap_or(u32::MAX)
1275 {
1276 to_visit.push(dep_id);
1277 break; }
1279 }
1280 }
1281 }
1282 }
1283 }
1284 }
1285
1286 while let Some(id) = to_visit.pop() {
1287 if !visited_for_propagation.insert(id) {
1288 continue; }
1290 affected.insert(id);
1291
1292 self.store.set_dirty(id, true);
1294
1295 let dependents = self.get_dependents(id);
1297 to_visit.extend(&dependents);
1298 }
1299
1300 self.dirty_vertices.extend(&affected);
1302
1303 affected.into_iter().collect()
1305 }
1306
1307 pub fn get_evaluation_vertices(&self) -> Vec<VertexId> {
1309 let mut combined = FxHashSet::default();
1310 combined.extend(&self.dirty_vertices);
1311 combined.extend(&self.volatile_vertices);
1312
1313 let mut result: Vec<VertexId> = combined
1314 .into_iter()
1315 .filter(|&id| {
1316 matches!(
1318 self.store.kind(id),
1319 VertexKind::FormulaScalar | VertexKind::FormulaArray
1320 )
1321 })
1322 .collect();
1323 result.sort_unstable();
1324 result
1325 }
1326
1327 pub fn clear_dirty_flags(&mut self, vertices: &[VertexId]) {
1329 for &vertex_id in vertices {
1330 self.store.set_dirty(vertex_id, false);
1331 self.dirty_vertices.remove(&vertex_id);
1332 }
1333 }
1334
1335 pub fn clear_volatile_flags(&mut self) {
1337 self.volatile_vertices.clear();
1338 }
1339
1340 pub(crate) fn redirty_volatiles(&mut self) {
1342 let volatile_ids: Vec<VertexId> = self.volatile_vertices.iter().copied().collect();
1343 for id in volatile_ids {
1344 self.mark_dirty(id);
1345 }
1346 }
1347
1348 fn extract_dependencies(
1350 &mut self,
1351 ast: &ASTNode,
1352 current_sheet_id: SheetId,
1353 ) -> ExtractDependenciesResult {
1354 let mut dependencies = FxHashSet::default();
1355 let mut range_dependencies = Vec::new();
1356 let mut created_placeholders = Vec::new();
1357 self.extract_dependencies_recursive(
1358 ast,
1359 current_sheet_id,
1360 &mut dependencies,
1361 &mut range_dependencies,
1362 &mut created_placeholders,
1363 )?;
1364
1365 let mut deduped_ranges = Vec::new();
1367 for range_ref in range_dependencies {
1368 if !deduped_ranges.contains(&range_ref) {
1369 deduped_ranges.push(range_ref);
1370 }
1371 }
1372
1373 Ok((
1374 dependencies.into_iter().collect(),
1375 deduped_ranges,
1376 created_placeholders,
1377 ))
1378 }
1379
1380 fn extract_dependencies_recursive(
1381 &mut self,
1382 ast: &ASTNode,
1383 current_sheet_id: SheetId,
1384 dependencies: &mut FxHashSet<VertexId>,
1385 range_dependencies: &mut Vec<ReferenceType>,
1386 created_placeholders: &mut Vec<CellRef>,
1387 ) -> Result<(), ExcelError> {
1388 match &ast.node_type {
1389 ASTNodeType::Reference { reference, .. } => {
1390 match reference {
1391 ReferenceType::Cell { .. } => {
1392 let vertex_id = self.get_or_create_vertex_for_reference(
1393 reference,
1394 current_sheet_id,
1395 created_placeholders,
1396 )?;
1397 dependencies.insert(vertex_id);
1398 }
1399 ReferenceType::Range {
1400 sheet,
1401 start_row,
1402 start_col,
1403 end_row,
1404 end_col,
1405 } => {
1406 let has_unbounded = start_row.is_none()
1408 || end_row.is_none()
1409 || start_col.is_none()
1410 || end_col.is_none();
1411 if has_unbounded {
1412 range_dependencies.push(reference.clone());
1413 } else {
1414 let sr = start_row.unwrap();
1415 let sc = start_col.unwrap();
1416 let er = end_row.unwrap();
1417 let ec = end_col.unwrap();
1418
1419 if sr > er || sc > ec {
1420 return Err(ExcelError::new(ExcelErrorKind::Ref));
1421 }
1422
1423 let height = er.saturating_sub(sr) + 1;
1424 let width = ec.saturating_sub(sc) + 1;
1425 let size = (width * height) as usize;
1426
1427 if size <= self.config.range_expansion_limit {
1428 let sheet_id = match sheet {
1430 Some(name) => self.resolve_existing_sheet_id(name)?,
1431 None => current_sheet_id,
1432 };
1433 for row in sr..=er {
1434 for col in sc..=ec {
1435 let coord = Coord::new(row, col, true, true);
1436 let addr = CellRef::new(sheet_id, coord);
1437 let vertex_id =
1438 self.get_or_create_vertex(&addr, created_placeholders);
1439 dependencies.insert(vertex_id);
1440 }
1441 }
1442 } else {
1443 range_dependencies.push(reference.clone());
1445 }
1446 }
1447 }
1448 ReferenceType::NamedRange(name) => {
1449 if let Some(definition) = self.resolve_name(name, current_sheet_id) {
1451 let definition = definition.clone();
1453
1454 match definition {
1455 NamedDefinition::Cell(cell_ref) => {
1456 let vertex_id =
1457 self.get_or_create_vertex(&cell_ref, created_placeholders);
1458 dependencies.insert(vertex_id);
1459 }
1460 NamedDefinition::Range(range_ref) => {
1461 let height = range_ref
1463 .end
1464 .coord
1465 .row
1466 .saturating_sub(range_ref.start.coord.row)
1467 + 1;
1468 let width = range_ref
1469 .end
1470 .coord
1471 .col
1472 .saturating_sub(range_ref.start.coord.col)
1473 + 1;
1474 let size = (width * height) as usize;
1475
1476 if size <= self.config.range_expansion_limit {
1477 for row in
1479 range_ref.start.coord.row..=range_ref.end.coord.row
1480 {
1481 for col in
1482 range_ref.start.coord.col..=range_ref.end.coord.col
1483 {
1484 let coord = Coord::new(row, col, true, true);
1485 let addr =
1486 CellRef::new(range_ref.start.sheet_id, coord);
1487 let vertex_id = self.get_or_create_vertex(
1488 &addr,
1489 created_placeholders,
1490 );
1491 dependencies.insert(vertex_id);
1492 }
1493 }
1494 } else {
1495 let sheet_name = self.sheet_name(range_ref.start.sheet_id);
1497 range_dependencies.push(ReferenceType::Range {
1498 sheet: Some(sheet_name.to_string()),
1499 start_row: Some(range_ref.start.coord.row),
1500 start_col: Some(range_ref.start.coord.col),
1501 end_row: Some(range_ref.end.coord.row),
1502 end_col: Some(range_ref.end.coord.col),
1503 });
1504 }
1505 }
1506 NamedDefinition::Formula {
1507 dependencies: formula_deps,
1508 range_deps,
1509 ..
1510 } => {
1511 dependencies.extend(formula_deps);
1513 range_dependencies.extend(range_deps);
1514 }
1515 }
1516
1517 } else {
1520 return Err(ExcelError::new(ExcelErrorKind::Name)
1521 .with_message(format!("Undefined name: {name}")));
1522 }
1523 }
1524 _ => {} }
1526 }
1527 ASTNodeType::BinaryOp { left, right, .. } => {
1528 self.extract_dependencies_recursive(
1529 left,
1530 current_sheet_id,
1531 dependencies,
1532 range_dependencies,
1533 created_placeholders,
1534 )?;
1535 self.extract_dependencies_recursive(
1536 right,
1537 current_sheet_id,
1538 dependencies,
1539 range_dependencies,
1540 created_placeholders,
1541 )?;
1542 }
1543 ASTNodeType::UnaryOp { expr, .. } => {
1544 self.extract_dependencies_recursive(
1545 expr,
1546 current_sheet_id,
1547 dependencies,
1548 range_dependencies,
1549 created_placeholders,
1550 )?;
1551 }
1552 ASTNodeType::Function { args, .. } => {
1553 for arg in args {
1554 self.extract_dependencies_recursive(
1555 arg,
1556 current_sheet_id,
1557 dependencies,
1558 range_dependencies,
1559 created_placeholders,
1560 )?;
1561 }
1562 }
1563 ASTNodeType::Array(rows) => {
1564 for row in rows {
1565 for cell in row {
1566 self.extract_dependencies_recursive(
1567 cell,
1568 current_sheet_id,
1569 dependencies,
1570 range_dependencies,
1571 created_placeholders,
1572 )?;
1573 }
1574 }
1575 }
1576 ASTNodeType::Literal(_) => {
1577 }
1579 }
1580 Ok(())
1581 }
1582
1583 fn get_or_create_vertex(
1584 &mut self,
1585 addr: &CellRef,
1586 created_placeholders: &mut Vec<CellRef>,
1587 ) -> VertexId {
1588 if let Some(&vertex_id) = self.cell_to_vertex.get(addr) {
1589 return vertex_id;
1590 }
1591
1592 created_placeholders.push(*addr);
1593 let packed_coord = PackedCoord::new(addr.coord.row, addr.coord.col);
1594 let vertex_id = self.store.allocate(packed_coord, addr.sheet_id, 0x00);
1595
1596 self.edges.add_vertex(packed_coord, vertex_id.0);
1598
1599 self.sheet_index_mut(addr.sheet_id)
1601 .add_vertex(packed_coord, vertex_id);
1602
1603 self.store.set_kind(vertex_id, VertexKind::Empty);
1604 self.cell_to_vertex.insert(*addr, vertex_id);
1605 vertex_id
1606 }
1607
1608 fn get_or_create_vertex_for_reference(
1610 &mut self,
1611 reference: &ReferenceType,
1612 current_sheet_id: SheetId,
1613 created_placeholders: &mut Vec<CellRef>,
1614 ) -> Result<VertexId, ExcelError> {
1615 match reference {
1616 ReferenceType::Cell { sheet, row, col } => {
1617 let sheet_id = match sheet {
1618 Some(name) => self.resolve_existing_sheet_id(name)?,
1619 None => current_sheet_id,
1620 };
1621 let coord = Coord::new(*row, *col, true, true);
1622 let addr = CellRef::new(sheet_id, coord);
1623 Ok(self.get_or_create_vertex(&addr, created_placeholders))
1624 }
1625 _ => Err(ExcelError::new(ExcelErrorKind::Value)
1626 .with_message("Expected a cell reference, but got a range or other type.")),
1627 }
1628 }
1629
1630 #[inline]
1631 fn is_ast_volatile(&self, ast: &ASTNode) -> bool {
1632 ast.contains_volatile()
1634 }
1635
1636 fn add_dependent_edges(&mut self, dependent: VertexId, dependencies: &[VertexId]) {
1637 self.edges.begin_batch();
1639
1640 let mut skip_deps: rustc_hash::FxHashSet<VertexId> = rustc_hash::FxHashSet::default();
1643 if self.pk_order.is_some() {
1644 if let Some(mut pk) = self.pk_order.take() {
1645 pk.ensure_nodes(std::iter::once(dependent));
1646 pk.ensure_nodes(dependencies.iter().copied());
1647 {
1648 let adapter = GraphAdapter { g: self };
1649 for &dep_id in dependencies {
1650 match pk.try_add_edge(&adapter, dep_id, dependent) {
1651 Ok(_) => {}
1652 Err(_cycle) => {
1653 if self.config.pk_reject_cycle_edges {
1654 skip_deps.insert(dep_id);
1655 } else {
1656 pk.rebuild_full(&adapter);
1657 }
1658 }
1659 }
1660 }
1661 } self.pk_order = Some(pk);
1663 }
1664 }
1665
1666 for &dep_id in dependencies {
1668 if self.config.pk_reject_cycle_edges && skip_deps.contains(&dep_id) {
1669 continue;
1670 }
1671 self.edges.add_edge(dependent, dep_id);
1672 #[cfg(test)]
1673 {
1674 self.instr.edges_added += 1;
1675 }
1676 }
1677
1678 self.edges.end_batch();
1679 }
1680
1681 fn add_dependent_edges_nobatch(&mut self, dependent: VertexId, dependencies: &[VertexId]) {
1683 let mut skip_deps: rustc_hash::FxHashSet<VertexId> = rustc_hash::FxHashSet::default();
1685 if self.pk_order.is_some() {
1686 if let Some(mut pk) = self.pk_order.take() {
1687 pk.ensure_nodes(std::iter::once(dependent));
1688 pk.ensure_nodes(dependencies.iter().copied());
1689 {
1690 let adapter = GraphAdapter { g: self };
1691 for &dep_id in dependencies {
1692 match pk.try_add_edge(&adapter, dep_id, dependent) {
1693 Ok(_) => {}
1694 Err(_cycle) => {
1695 if self.config.pk_reject_cycle_edges {
1696 skip_deps.insert(dep_id);
1697 } else {
1698 pk.rebuild_full(&adapter);
1699 }
1700 }
1701 }
1702 }
1703 }
1704 self.pk_order = Some(pk);
1705 }
1706 }
1707
1708 for &dep_id in dependencies {
1709 if self.config.pk_reject_cycle_edges && skip_deps.contains(&dep_id) {
1710 continue;
1711 }
1712 self.edges.add_edge(dependent, dep_id);
1713 #[cfg(test)]
1714 {
1715 self.instr.edges_added += 1;
1716 }
1717 }
1718 }
1719
1720 pub fn bulk_set_formulas<I>(&mut self, sheet: &str, items: I) -> Result<usize, ExcelError>
1722 where
1723 I: IntoIterator<Item = (u32, u32, ASTNode)>,
1724 {
1725 use formualizer_parse::parser::CollectPolicy;
1726 let sheet_id = self.sheet_id_mut(sheet);
1727
1728 let collected: Vec<(u32, u32, ASTNode)> = items.into_iter().collect();
1730 if collected.is_empty() {
1731 return Ok(0);
1732 }
1733
1734 let tiny_refs = collected.iter().map(|(r, c, ast)| (sheet, *r, *c, ast));
1736 let vol_flags: Vec<bool> = collected
1737 .iter()
1738 .map(|(_, _, ast)| self.is_ast_volatile(ast))
1739 .collect();
1740 let policy = CollectPolicy {
1741 expand_small_ranges: true,
1742 range_expansion_limit: self.config.range_expansion_limit,
1743 include_names: true,
1744 };
1745 let plan = crate::engine::plan::build_dependency_plan(
1746 &mut self.sheet_reg,
1747 tiny_refs,
1748 &policy,
1749 Some(&vol_flags),
1750 )?;
1751
1752 let mut created_placeholders: Vec<CellRef> = Vec::new();
1754
1755 let mut target_vids: Vec<VertexId> = Vec::with_capacity(plan.formula_targets.len());
1757 for (sid, pc) in &plan.formula_targets {
1758 let addr = CellRef::new(*sid, Coord::new(pc.row(), pc.col(), true, true));
1759 let vid = if let Some(&existing) = self.cell_to_vertex.get(&addr) {
1760 existing
1761 } else {
1762 self.get_or_create_vertex(&addr, &mut created_placeholders)
1763 };
1764 target_vids.push(vid);
1765 }
1766
1767 let mut dep_vids: Vec<VertexId> = Vec::with_capacity(plan.global_cells.len());
1769 for (sid, pc) in &plan.global_cells {
1770 let addr = CellRef::new(*sid, Coord::new(pc.row(), pc.col(), true, true));
1771 let vid = if let Some(&existing) = self.cell_to_vertex.get(&addr) {
1772 existing
1773 } else {
1774 self.get_or_create_vertex(&addr, &mut created_placeholders)
1775 };
1776 dep_vids.push(vid);
1777 }
1778
1779 let ast_ids = self
1781 .data_store
1782 .store_asts_batch(collected.iter().map(|(_, _, ast)| ast), &self.sheet_reg);
1783
1784 for (i, &tvid) in target_vids.iter().enumerate() {
1785 if self.vertex_formulas.contains_key(&tvid) {
1787 self.remove_dependent_edges(tvid);
1788 }
1789 self.store.set_kind(tvid, VertexKind::FormulaScalar);
1790 self.store.set_dirty(tvid, true);
1791 self.vertex_values.remove(&tvid);
1792 self.vertex_formulas.insert(tvid, ast_ids[i]);
1793 if vol_flags.get(i).copied().unwrap_or(false) {
1794 self.store.set_volatile(tvid, true);
1795 self.volatile_vertices.insert(tvid);
1796 }
1797 }
1798
1799 self.edges.begin_batch();
1801 for (i, tvid) in target_vids.iter().copied().enumerate() {
1802 if let Some(indices) = plan.per_formula_cells.get(i) {
1804 let mut deps: Vec<VertexId> = Vec::with_capacity(indices.len());
1805 for &idx in indices {
1806 if let Some(vid) = dep_vids.get(idx as usize) {
1807 deps.push(*vid);
1808 }
1809 }
1810 self.add_dependent_edges_nobatch(tvid, &deps);
1811 }
1812
1813 if let Some(rks) = plan.per_formula_ranges.get(i) {
1815 let mut range_refs: Vec<ReferenceType> = Vec::with_capacity(rks.len());
1816 use crate::engine::plan::RangeKey as RK;
1817 for rk in rks {
1818 match rk {
1819 RK::Rect { sheet, start, end } => range_refs.push(ReferenceType::Range {
1820 sheet: Some(self.sheet_name(*sheet).to_string()),
1821 start_row: Some(start.row()),
1822 start_col: Some(start.col()),
1823 end_row: Some(end.row()),
1824 end_col: Some(end.col()),
1825 }),
1826 RK::WholeRow { sheet, row } => range_refs.push(ReferenceType::Range {
1827 sheet: Some(self.sheet_name(*sheet).to_string()),
1828 start_row: Some(*row),
1829 start_col: None,
1830 end_row: Some(*row),
1831 end_col: None,
1832 }),
1833 RK::WholeCol { sheet, col } => range_refs.push(ReferenceType::Range {
1834 sheet: Some(self.sheet_name(*sheet).to_string()),
1835 start_row: None,
1836 start_col: Some(*col),
1837 end_row: None,
1838 end_col: Some(*col),
1839 }),
1840 RK::OpenRect { sheet, start, end } => {
1841 range_refs.push(ReferenceType::Range {
1842 sheet: Some(self.sheet_name(*sheet).to_string()),
1843 start_row: start.map(|p| p.row()),
1844 start_col: start.map(|p| p.col()),
1845 end_row: end.map(|p| p.row()),
1846 end_col: end.map(|p| p.col()),
1847 })
1848 }
1849 }
1850 }
1851 self.add_range_dependent_edges(tvid, &range_refs, sheet_id);
1852 }
1853 }
1854 self.edges.end_batch();
1855
1856 Ok(collected.len())
1857 }
1858
1859 pub fn add_dependency_edge(&mut self, dependent: VertexId, dependency: VertexId) {
1861 if dependent == dependency {
1862 return;
1863 }
1864 if self.pk_order.is_some() {
1866 if let Some(mut pk) = self.pk_order.take() {
1867 pk.ensure_nodes(std::iter::once(dependent));
1868 pk.ensure_nodes(std::iter::once(dependency));
1869 let adapter = GraphAdapter { g: self };
1870 if pk.try_add_edge(&adapter, dependency, dependent).is_err() {
1871 pk.rebuild_full(&adapter);
1873 }
1874 self.pk_order = Some(pk);
1875 }
1876 }
1877 self.edges.add_edge(dependent, dependency);
1878 self.store.set_dirty(dependent, true);
1879 self.dirty_vertices.insert(dependent);
1880 }
1881
1882 fn add_range_dependent_edges(
1883 &mut self,
1884 dependent: VertexId,
1885 ranges: &[ReferenceType],
1886 current_sheet_id: SheetId,
1887 ) {
1888 if ranges.is_empty() {
1889 return;
1890 }
1891 self.formula_to_range_deps
1892 .insert(dependent, ranges.to_vec());
1893
1894 for range in ranges {
1895 if let ReferenceType::Range {
1896 sheet,
1897 start_row,
1898 start_col,
1899 end_row,
1900 end_col,
1901 } = range
1902 {
1903 let sheet_id = match sheet {
1904 Some(name) => self.sheet_id_mut(name),
1905 None => current_sheet_id,
1906 };
1907 let s_row = *start_row;
1908 let e_row = *end_row;
1909 let s_col = *start_col;
1910 let e_col = *end_col;
1911
1912 let col_stripes = (s_row.is_none() && e_row.is_none())
1914 || (s_col.is_some() && e_col.is_some() && (s_row.is_none() || e_row.is_none())); let row_stripes = (s_col.is_none() && e_col.is_none())
1916 || (s_row.is_some() && e_row.is_some() && (s_col.is_none() || e_col.is_none())); if col_stripes && !row_stripes {
1919 let sc = s_col.unwrap_or(1);
1920 let ec = e_col.unwrap_or(sc);
1921 for col in sc..=ec {
1922 let key = StripeKey {
1923 sheet_id,
1924 stripe_type: StripeType::Column,
1925 index: col,
1926 };
1927 self.stripe_to_dependents
1928 .entry(key.clone())
1929 .or_default()
1930 .insert(dependent);
1931 #[cfg(test)]
1932 {
1933 if self.stripe_to_dependents.get(&key).map(|s| s.len()) == Some(1) {
1935 self.instr.stripe_inserts += 1;
1936 }
1937 }
1938 }
1939 continue;
1940 }
1941
1942 if row_stripes && !col_stripes {
1943 let sr = s_row.unwrap_or(1);
1944 let er = e_row.unwrap_or(sr);
1945 for row in sr..=er {
1946 let key = StripeKey {
1947 sheet_id,
1948 stripe_type: StripeType::Row,
1949 index: row,
1950 };
1951 self.stripe_to_dependents
1952 .entry(key.clone())
1953 .or_default()
1954 .insert(dependent);
1955 #[cfg(test)]
1956 {
1957 if self.stripe_to_dependents.get(&key).map(|s| s.len()) == Some(1) {
1958 self.instr.stripe_inserts += 1;
1959 }
1960 }
1961 }
1962 continue;
1963 }
1964
1965 let start_row = s_row.unwrap_or(1);
1967 let start_col = s_col.unwrap_or(1);
1968 let end_row = e_row.unwrap_or(start_row);
1969 let end_col = e_col.unwrap_or(start_col);
1970
1971 let height = end_row.saturating_sub(start_row) + 1;
1972 let width = end_col.saturating_sub(start_col) + 1;
1973
1974 if self.config.enable_block_stripes && height > 1 && width > 1 {
1975 let start_block_row = start_row / BLOCK_H;
1976 let end_block_row = end_row / BLOCK_H;
1977 let start_block_col = start_col / BLOCK_W;
1978 let end_block_col = end_col / BLOCK_W;
1979
1980 for block_row in start_block_row..=end_block_row {
1981 for block_col in start_block_col..=end_block_col {
1982 let key = StripeKey {
1983 sheet_id,
1984 stripe_type: StripeType::Block,
1985 index: block_index(block_row * BLOCK_H, block_col * BLOCK_W),
1986 };
1987 self.stripe_to_dependents
1988 .entry(key.clone())
1989 .or_default()
1990 .insert(dependent);
1991 #[cfg(test)]
1992 {
1993 if self.stripe_to_dependents.get(&key).map(|s| s.len()) == Some(1) {
1994 self.instr.stripe_inserts += 1;
1995 }
1996 }
1997 }
1998 }
1999 } else if height > width {
2000 for col in start_col..=end_col {
2002 let key = StripeKey {
2003 sheet_id,
2004 stripe_type: StripeType::Column,
2005 index: col,
2006 };
2007 self.stripe_to_dependents
2008 .entry(key.clone())
2009 .or_default()
2010 .insert(dependent);
2011 #[cfg(test)]
2012 {
2013 if self.stripe_to_dependents.get(&key).map(|s| s.len()) == Some(1) {
2014 self.instr.stripe_inserts += 1;
2015 }
2016 }
2017 }
2018 } else {
2019 for row in start_row..=end_row {
2021 let key = StripeKey {
2022 sheet_id,
2023 stripe_type: StripeType::Row,
2024 index: row,
2025 };
2026 self.stripe_to_dependents
2027 .entry(key.clone())
2028 .or_default()
2029 .insert(dependent);
2030 #[cfg(test)]
2031 {
2032 if self.stripe_to_dependents.get(&key).map(|s| s.len()) == Some(1) {
2033 self.instr.stripe_inserts += 1;
2034 }
2035 }
2036 }
2037 }
2038 }
2039 }
2040 }
2041
2042 pub fn add_range_deps_from_keys(
2044 &mut self,
2045 dependent: VertexId,
2046 keys: &[crate::engine::plan::RangeKey],
2047 current_sheet_id: SheetId,
2048 ) {
2049 use crate::engine::plan::RangeKey as RK;
2050 if keys.is_empty() {
2051 return;
2052 }
2053 let mut ranges: Vec<ReferenceType> = Vec::with_capacity(keys.len());
2055 for k in keys {
2056 match k {
2057 RK::Rect { sheet, start, end } => ranges.push(ReferenceType::Range {
2058 sheet: Some(self.sheet_name(*sheet).to_string()),
2059 start_row: Some(start.row()),
2060 start_col: Some(start.col()),
2061 end_row: Some(end.row()),
2062 end_col: Some(end.col()),
2063 }),
2064 RK::WholeRow { sheet, row } => ranges.push(ReferenceType::Range {
2065 sheet: Some(self.sheet_name(*sheet).to_string()),
2066 start_row: Some(*row),
2067 start_col: None,
2068 end_row: Some(*row),
2069 end_col: None,
2070 }),
2071 RK::WholeCol { sheet, col } => ranges.push(ReferenceType::Range {
2072 sheet: Some(self.sheet_name(*sheet).to_string()),
2073 start_row: None,
2074 start_col: Some(*col),
2075 end_row: None,
2076 end_col: Some(*col),
2077 }),
2078 RK::OpenRect { sheet, start, end } => ranges.push(ReferenceType::Range {
2079 sheet: Some(self.sheet_name(*sheet).to_string()),
2080 start_row: start.map(|p| p.row()),
2081 start_col: start.map(|p| p.col()),
2082 end_row: end.map(|p| p.row()),
2083 end_col: end.map(|p| p.col()),
2084 }),
2085 }
2086 }
2087 self.formula_to_range_deps.insert(dependent, ranges.clone());
2089
2090 for r in &ranges {
2092 if let ReferenceType::Range {
2093 sheet: _,
2094 start_row,
2095 start_col,
2096 end_row,
2097 end_col,
2098 } = r
2099 {
2100 let s_row = *start_row;
2102 let e_row = *end_row;
2103 let s_col = *start_col;
2104 let e_col = *end_col;
2105 let col_stripes = (s_row.is_none() && e_row.is_none())
2106 || (s_col.is_some() && e_col.is_some() && (s_row.is_none() || e_row.is_none()));
2107 let row_stripes = (s_col.is_none() && e_col.is_none())
2108 || (s_row.is_some() && e_row.is_some() && (s_col.is_none() || e_col.is_none()));
2109 if col_stripes && !row_stripes {
2110 let sc = s_col.unwrap_or(1);
2111 let ec = e_col.unwrap_or(sc);
2112 for col in sc..=ec {
2113 let key = StripeKey {
2114 sheet_id: current_sheet_id,
2115 stripe_type: StripeType::Column,
2116 index: col,
2117 };
2118 self.stripe_to_dependents
2119 .entry(key)
2120 .or_default()
2121 .insert(dependent);
2122 }
2123 continue;
2124 }
2125 if row_stripes && !col_stripes {
2126 let sr = s_row.unwrap_or(1);
2127 let er = e_row.unwrap_or(sr);
2128 for row in sr..=er {
2129 let key = StripeKey {
2130 sheet_id: current_sheet_id,
2131 stripe_type: StripeType::Row,
2132 index: row,
2133 };
2134 self.stripe_to_dependents
2135 .entry(key)
2136 .or_default()
2137 .insert(dependent);
2138 }
2139 continue;
2140 }
2141 if let (Some(sr), Some(sc), Some(er), Some(ec)) = (s_row, s_col, e_row, e_col) {
2143 let key = StripeKey {
2144 sheet_id: current_sheet_id,
2145 stripe_type: StripeType::Block,
2146 index: 0,
2147 };
2148 self.stripe_to_dependents
2149 .entry(key)
2150 .or_default()
2151 .insert(dependent);
2152 }
2153 }
2154 }
2155 }
2156
2157 fn remove_dependent_edges(&mut self, vertex: VertexId) {
2158 let dependencies = self.edges.out_edges(vertex);
2160
2161 self.edges.begin_batch();
2162 if self.pk_order.is_some() {
2163 if let Some(mut pk) = self.pk_order.take() {
2164 for dep in &dependencies {
2165 pk.remove_edge(*dep, vertex);
2166 }
2167 self.pk_order = Some(pk);
2168 }
2169 }
2170 for dep in dependencies {
2171 self.edges.remove_edge(vertex, dep);
2172 }
2173 self.edges.end_batch();
2174
2175 if let Some(old_ranges) = self.formula_to_range_deps.remove(&vertex) {
2177 let old_sheet_id = self.store.sheet_id(vertex);
2178
2179 for range in &old_ranges {
2180 if let ReferenceType::Range {
2181 sheet,
2182 start_row,
2183 start_col,
2184 end_row,
2185 end_col,
2186 } = range
2187 {
2188 let sheet_id = match sheet {
2189 Some(name) => self.sheet_reg.get_id(name).unwrap_or(old_sheet_id),
2190 None => old_sheet_id,
2191 };
2192 let s_row = *start_row;
2193 let e_row = *end_row;
2194 let s_col = *start_col;
2195 let e_col = *end_col;
2196
2197 let mut keys_to_clean = FxHashSet::default();
2198
2199 let col_stripes = (s_row.is_none() && e_row.is_none())
2200 || (s_col.is_some()
2201 && e_col.is_some()
2202 && (s_row.is_none() || e_row.is_none()));
2203 let row_stripes = (s_col.is_none() && e_col.is_none())
2204 || (s_row.is_some()
2205 && e_row.is_some()
2206 && (s_col.is_none() || e_col.is_none()));
2207
2208 if col_stripes && !row_stripes {
2209 let sc = s_col.unwrap_or(1);
2210 let ec = e_col.unwrap_or(sc);
2211 for col in sc..=ec {
2212 keys_to_clean.insert(StripeKey {
2213 sheet_id,
2214 stripe_type: StripeType::Column,
2215 index: col,
2216 });
2217 }
2218 } else if row_stripes && !col_stripes {
2219 let sr = s_row.unwrap_or(1);
2220 let er = e_row.unwrap_or(sr);
2221 for row in sr..=er {
2222 keys_to_clean.insert(StripeKey {
2223 sheet_id,
2224 stripe_type: StripeType::Row,
2225 index: row,
2226 });
2227 }
2228 } else {
2229 let start_row = s_row.unwrap_or(1);
2230 let start_col = s_col.unwrap_or(1);
2231 let end_row = e_row.unwrap_or(start_row);
2232 let end_col = e_col.unwrap_or(start_col);
2233
2234 let height = end_row.saturating_sub(start_row) + 1;
2235 let width = end_col.saturating_sub(start_col) + 1;
2236
2237 if self.config.enable_block_stripes && height > 1 && width > 1 {
2238 let start_block_row = start_row / BLOCK_H;
2239 let end_block_row = end_row / BLOCK_H;
2240 let start_block_col = start_col / BLOCK_W;
2241 let end_block_col = end_col / BLOCK_W;
2242
2243 for block_row in start_block_row..=end_block_row {
2244 for block_col in start_block_col..=end_block_col {
2245 keys_to_clean.insert(StripeKey {
2246 sheet_id,
2247 stripe_type: StripeType::Block,
2248 index: block_index(
2249 block_row * BLOCK_H,
2250 block_col * BLOCK_W,
2251 ),
2252 });
2253 }
2254 }
2255 } else if height > width {
2256 for col in start_col..=end_col {
2258 keys_to_clean.insert(StripeKey {
2259 sheet_id,
2260 stripe_type: StripeType::Column,
2261 index: col,
2262 });
2263 }
2264 } else {
2265 for row in start_row..=end_row {
2267 keys_to_clean.insert(StripeKey {
2268 sheet_id,
2269 stripe_type: StripeType::Row,
2270 index: row,
2271 });
2272 }
2273 }
2274 }
2275
2276 for key in keys_to_clean {
2277 if let Some(dependents) = self.stripe_to_dependents.get_mut(&key) {
2278 dependents.remove(&vertex);
2279 if dependents.is_empty() {
2280 self.stripe_to_dependents.remove(&key);
2281 #[cfg(test)]
2282 {
2283 self.instr.stripe_removes += 1;
2284 }
2285 }
2286 }
2287 }
2288 }
2289 }
2290 }
2291 }
2292
2293 pub(crate) fn update_vertex_value(&mut self, vertex_id: VertexId, value: LiteralValue) {
2299 let value_ref = self.data_store.store_value(value);
2300 self.vertex_values.insert(vertex_id, value_ref);
2301 }
2302
2303 pub fn plan_spill_region(
2305 &self,
2306 anchor: VertexId,
2307 target_cells: &[CellRef],
2308 ) -> Result<(), ExcelError> {
2309 use formualizer_common::{ExcelErrorExtra, ExcelErrorKind};
2310 let (expected_rows, expected_cols) = if target_cells.is_empty() {
2312 (0u32, 0u32)
2313 } else {
2314 let mut min_r = u32::MAX;
2315 let mut max_r = 0u32;
2316 let mut min_c = u32::MAX;
2317 let mut max_c = 0u32;
2318 for cell in target_cells {
2319 let r = cell.coord.row;
2320 let c = cell.coord.col;
2321 if r < min_r {
2322 min_r = r;
2323 }
2324 if r > max_r {
2325 max_r = r;
2326 }
2327 if c < min_c {
2328 min_c = c;
2329 }
2330 if c > max_c {
2331 max_c = c;
2332 }
2333 }
2334 (
2335 max_r.saturating_sub(min_r).saturating_add(1),
2336 max_c.saturating_sub(min_c).saturating_add(1),
2337 )
2338 };
2339 for cell in target_cells {
2341 let owned_by_anchor = match self.spill_cell_to_anchor.get(cell) {
2343 Some(&existing_anchor) if existing_anchor == anchor => true,
2344 Some(_other) => {
2345 return Err(ExcelError::new(ExcelErrorKind::Spill)
2346 .with_message("BlockedBySpill")
2347 .with_extra(ExcelErrorExtra::Spill {
2348 expected_rows,
2349 expected_cols,
2350 }));
2351 }
2352 None => false,
2353 };
2354
2355 if owned_by_anchor {
2356 continue;
2357 }
2358
2359 if let Some(&vid) = self.cell_to_vertex.get(cell) {
2361 if vid != anchor {
2362 match self.store.kind(vid) {
2364 VertexKind::FormulaScalar | VertexKind::FormulaArray => {
2365 return Err(ExcelError::new(ExcelErrorKind::Spill)
2366 .with_message("BlockedByFormula")
2367 .with_extra(ExcelErrorExtra::Spill {
2368 expected_rows,
2369 expected_cols,
2370 }));
2371 }
2372 _ => {
2373 if let Some(vref) = self.vertex_values.get(&vid) {
2375 let v = self.data_store.retrieve_value(*vref);
2376 if !matches!(v, LiteralValue::Empty) {
2377 return Err(ExcelError::new(ExcelErrorKind::Spill)
2378 .with_message("BlockedByValue")
2379 .with_extra(ExcelErrorExtra::Spill {
2380 expected_rows,
2381 expected_cols,
2382 }));
2383 }
2384 }
2385 }
2386 }
2387 }
2388 }
2389 }
2390 Ok(())
2391 }
2392
2393 pub fn commit_spill_region_atomic_with_fault(
2400 &mut self,
2401 anchor: VertexId,
2402 target_cells: Vec<CellRef>,
2403 values: Vec<Vec<LiteralValue>>,
2404 fault_after_ops: Option<usize>,
2405 ) -> Result<(), ExcelError> {
2406 use rustc_hash::FxHashSet;
2407
2408 let prev_cells = self
2410 .spill_anchor_to_cells
2411 .get(&anchor)
2412 .cloned()
2413 .unwrap_or_default();
2414 let new_set: FxHashSet<CellRef> = target_cells.iter().copied().collect();
2415 let prev_set: FxHashSet<CellRef> = prev_cells.iter().copied().collect();
2416
2417 #[derive(Clone)]
2419 struct Op {
2420 sheet: String,
2421 row: u32,
2422 col: u32,
2423 new_value: LiteralValue,
2424 }
2425 let mut ops: Vec<Op> = Vec::new();
2426
2427 for cell in prev_cells.iter() {
2429 if !new_set.contains(cell) {
2430 let sheet = self.sheet_name(cell.sheet_id).to_string();
2431 ops.push(Op {
2432 sheet,
2433 row: cell.coord.row,
2434 col: cell.coord.col,
2435 new_value: LiteralValue::Empty,
2436 });
2437 }
2438 }
2439
2440 if !target_cells.is_empty() {
2442 let first = target_cells.first().copied().unwrap();
2443 let row0 = first.coord.row;
2444 let col0 = first.coord.col;
2445 let sheet = self.sheet_name(first.sheet_id).to_string();
2446 for (r_off, row_vals) in values.iter().enumerate() {
2447 for (c_off, v) in row_vals.iter().enumerate() {
2448 ops.push(Op {
2449 sheet: sheet.clone(),
2450 row: row0 + r_off as u32,
2451 col: col0 + c_off as u32,
2452 new_value: v.clone(),
2453 });
2454 }
2455 }
2456 }
2457
2458 #[derive(Clone)]
2460 struct OldVal {
2461 present: bool,
2462 value: LiteralValue,
2463 }
2464 let mut old_values: Vec<((String, u32, u32), OldVal)> = Vec::with_capacity(ops.len());
2465
2466 for op in &ops {
2468 let old = self
2469 .get_cell_value(&op.sheet, op.row, op.col)
2470 .unwrap_or(LiteralValue::Empty);
2471 let present = true; old_values.push((
2473 (op.sheet.clone(), op.row, op.col),
2474 OldVal {
2475 present,
2476 value: old,
2477 },
2478 ));
2479 }
2480
2481 for (applied, op) in ops.iter().enumerate() {
2483 if let Some(n) = fault_after_ops {
2484 if applied == n {
2485 for idx in (0..applied).rev() {
2486 let ((ref sheet, row, col), ref old) = old_values[idx];
2487 let _ = self.set_cell_value(sheet, row, col, old.value.clone());
2488 }
2489 return Err(ExcelError::new(ExcelErrorKind::Error)
2490 .with_message("Injected persistence fault during spill commit"));
2491 }
2492 }
2493 let _ = self.set_cell_value(&op.sheet, op.row, op.col, op.new_value.clone());
2494 }
2495
2496 for cell in prev_cells.iter() {
2499 if !new_set.contains(cell) {
2500 self.spill_cell_to_anchor.remove(cell);
2501 }
2502 }
2503 for cell in &target_cells {
2505 self.spill_cell_to_anchor.insert(*cell, anchor);
2506 }
2507 self.spill_anchor_to_cells.insert(anchor, target_cells);
2508 Ok(())
2509 }
2510
2511 pub fn clear_spill_region(&mut self, anchor: VertexId) {
2513 if let Some(cells) = self.spill_anchor_to_cells.remove(&anchor) {
2514 for cell in cells {
2515 let sheet = self.sheet_name(cell.sheet_id).to_string();
2516 let _ = self.set_cell_value(
2517 &sheet,
2518 cell.coord.row,
2519 cell.coord.col,
2520 LiteralValue::Empty,
2521 );
2522 self.spill_cell_to_anchor.remove(&cell);
2523 }
2524 }
2525 }
2526
2527 pub(crate) fn vertex_exists(&self, vertex_id: VertexId) -> bool {
2529 if vertex_id.0 < FIRST_NORMAL_VERTEX {
2530 return false;
2531 }
2532 let index = (vertex_id.0 - FIRST_NORMAL_VERTEX) as usize;
2533 index < self.store.len()
2534 }
2535
2536 pub(crate) fn get_vertex_kind(&self, vertex_id: VertexId) -> VertexKind {
2538 self.store.kind(vertex_id)
2539 }
2540
2541 pub(crate) fn get_vertex_sheet_id(&self, vertex_id: VertexId) -> SheetId {
2543 self.store.sheet_id(vertex_id)
2544 }
2545
2546 pub fn get_formula(&self, vertex_id: VertexId) -> Option<ASTNode> {
2548 self.vertex_formulas
2549 .get(&vertex_id)
2550 .and_then(|&ast_id| self.data_store.retrieve_ast(ast_id, &self.sheet_reg))
2551 }
2552
2553 pub fn get_value(&self, vertex_id: VertexId) -> Option<LiteralValue> {
2555 self.vertex_values
2556 .get(&vertex_id)
2557 .map(|&value_ref| self.data_store.retrieve_value(value_ref))
2558 }
2559
2560 pub(crate) fn get_cell_ref(&self, vertex_id: VertexId) -> Option<CellRef> {
2562 let packed_coord = self.store.coord(vertex_id);
2563 let sheet_id = self.store.sheet_id(vertex_id);
2564 let coord = Coord::new(packed_coord.row(), packed_coord.col(), true, true);
2565 Some(CellRef::new(sheet_id, coord))
2566 }
2567
2568 pub(crate) fn make_cell_ref_internal(&self, sheet_id: SheetId, row: u32, col: u32) -> CellRef {
2570 let coord = Coord::new(row, col, true, true);
2571 CellRef::new(sheet_id, coord)
2572 }
2573
2574 pub fn make_cell_ref(&self, sheet_name: &str, row: u32, col: u32) -> CellRef {
2576 let sheet_id = self.sheet_reg.get_id(sheet_name).unwrap_or(0);
2577 self.make_cell_ref_internal(sheet_id, row, col)
2578 }
2579
2580 pub(crate) fn is_dirty(&self, vertex_id: VertexId) -> bool {
2582 self.store.is_dirty(vertex_id)
2583 }
2584
2585 pub(crate) fn is_volatile(&self, vertex_id: VertexId) -> bool {
2587 self.store.is_volatile(vertex_id)
2588 }
2589
2590 pub fn get_vertex_id_for_address(&self, addr: &CellRef) -> Option<&VertexId> {
2592 self.cell_to_vertex.get(addr)
2593 }
2594
2595 #[cfg(test)]
2596 pub fn cell_to_vertex(&self) -> &FxHashMap<CellRef, VertexId> {
2597 &self.cell_to_vertex
2598 }
2599
2600 pub(crate) fn get_dependencies(&self, vertex_id: VertexId) -> Vec<VertexId> {
2602 self.edges.out_edges(vertex_id)
2603 }
2604
2605 pub(crate) fn has_self_loop(&self, vertex_id: VertexId) -> bool {
2607 self.edges.out_edges(vertex_id).contains(&vertex_id)
2608 }
2609
2610 pub(crate) fn get_dependents(&self, vertex_id: VertexId) -> Vec<VertexId> {
2613 if self.edges.delta_size() > 0 {
2616 let mut dependents = Vec::new();
2618 for (&_addr, &vid) in &self.cell_to_vertex {
2619 let out_edges = self.edges.out_edges(vid);
2620 if out_edges.contains(&vertex_id) {
2621 dependents.push(vid);
2622 }
2623 }
2624 dependents
2625 } else {
2626 self.edges.in_edges(vertex_id).to_vec()
2628 }
2629 }
2630
2631 #[doc(hidden)]
2635 pub fn snapshot_vertex(&self, id: VertexId) -> crate::engine::VertexSnapshot {
2636 let coord = self.store.coord(id);
2637 let sheet_id = self.store.sheet_id(id);
2638 let kind = self.store.kind(id);
2639 let flags = self.store.flags(id);
2640
2641 let value_ref = self.vertex_values.get(&id).copied();
2643 let formula_ref = self.vertex_formulas.get(&id).copied();
2644
2645 let out_edges = self.get_dependencies(id);
2647
2648 crate::engine::VertexSnapshot {
2649 coord,
2650 sheet_id,
2651 kind,
2652 flags,
2653 value_ref,
2654 formula_ref,
2655 out_edges,
2656 }
2657 }
2658
2659 #[doc(hidden)]
2661 pub fn remove_all_edges(&mut self, id: VertexId) {
2662 self.edges.begin_batch();
2664
2665 self.remove_dependent_edges(id);
2667
2668 self.edges.rebuild();
2671
2672 let dependents = self.get_dependents(id);
2674 if self.pk_order.is_some() {
2675 if let Some(mut pk) = self.pk_order.take() {
2676 for dependent in &dependents {
2677 pk.remove_edge(id, *dependent);
2678 }
2679 self.pk_order = Some(pk);
2680 }
2681 }
2682 for dependent in dependents {
2683 self.edges.remove_edge(dependent, id);
2684 }
2685
2686 self.edges.end_batch();
2688 }
2689
2690 #[doc(hidden)]
2692 pub fn mark_as_ref_error(&mut self, id: VertexId) {
2693 let error = LiteralValue::Error(ExcelError::new(ExcelErrorKind::Ref));
2694 let value_ref = self.data_store.store_value(error);
2695 self.vertex_values.insert(id, value_ref);
2696 self.store.set_dirty(id, true);
2697 self.dirty_vertices.insert(id);
2698 }
2699
2700 pub fn is_ref_error(&self, id: VertexId) -> bool {
2702 if let Some(value_ref) = self.vertex_values.get(&id) {
2703 let value = self.data_store.retrieve_value(*value_ref);
2704 if let LiteralValue::Error(err) = value {
2705 return err.kind == ExcelErrorKind::Ref;
2706 }
2707 }
2708 false
2709 }
2710
2711 #[doc(hidden)]
2713 pub fn mark_dependents_dirty(&mut self, id: VertexId) {
2714 let dependents = self.get_dependents(id);
2715 for dep_id in dependents {
2716 self.store.set_dirty(dep_id, true);
2717 self.dirty_vertices.insert(dep_id);
2718 }
2719 }
2720
2721 #[doc(hidden)]
2723 pub fn mark_volatile(&mut self, id: VertexId, volatile: bool) {
2724 self.store.set_volatile(id, volatile);
2725 if volatile {
2726 self.volatile_vertices.insert(id);
2727 } else {
2728 self.volatile_vertices.remove(&id);
2729 }
2730 }
2731
2732 #[doc(hidden)]
2734 pub fn set_coord(&mut self, id: VertexId, coord: PackedCoord) {
2735 self.store.set_coord(id, coord);
2736 }
2737
2738 #[doc(hidden)]
2740 pub fn update_edge_coord(&mut self, id: VertexId, coord: PackedCoord) {
2741 self.edges.update_coord(id, coord);
2742 }
2743
2744 #[doc(hidden)]
2746 pub fn mark_deleted(&mut self, id: VertexId, deleted: bool) {
2747 self.store.mark_deleted(id, deleted);
2748 }
2749
2750 #[doc(hidden)]
2752 pub fn set_kind(&mut self, id: VertexId, kind: VertexKind) {
2753 self.store.set_kind(id, kind);
2754 }
2755
2756 #[doc(hidden)]
2758 pub fn set_dirty(&mut self, id: VertexId, dirty: bool) {
2759 self.store.set_dirty(id, dirty);
2760 if dirty {
2761 self.dirty_vertices.insert(id);
2762 } else {
2763 self.dirty_vertices.remove(&id);
2764 }
2765 }
2766
2767 #[cfg(test)]
2769 pub(crate) fn get_kind(&self, id: VertexId) -> VertexKind {
2770 self.store.kind(id)
2771 }
2772
2773 #[cfg(test)]
2775 pub(crate) fn get_flags(&self, id: VertexId) -> u8 {
2776 self.store.flags(id)
2777 }
2778
2779 #[cfg(test)]
2781 pub(crate) fn is_deleted(&self, id: VertexId) -> bool {
2782 self.store.is_deleted(id)
2783 }
2784
2785 #[doc(hidden)]
2787 pub fn rebuild_edges(&mut self) {
2788 self.edges.rebuild();
2789 }
2790
2791 #[doc(hidden)]
2793 pub fn edges_delta_size(&self) -> usize {
2794 self.edges.delta_size()
2795 }
2796
2797 pub fn get_vertex_for_cell(&self, addr: &CellRef) -> Option<VertexId> {
2799 self.cell_to_vertex.get(addr).copied()
2800 }
2801
2802 pub fn get_coord(&self, id: VertexId) -> PackedCoord {
2804 self.store.coord(id)
2805 }
2806
2807 pub fn get_sheet_id(&self, id: VertexId) -> SheetId {
2809 self.store.sheet_id(id)
2810 }
2811
2812 pub fn vertices_in_sheet(&self, sheet_id: SheetId) -> impl Iterator<Item = VertexId> + '_ {
2814 self.store
2815 .all_vertices()
2816 .filter(move |&id| self.vertex_exists(id) && self.store.sheet_id(id) == sheet_id)
2817 }
2818
2819 pub fn vertex_has_formula(&self, id: VertexId) -> bool {
2821 self.vertex_formulas.contains_key(&id)
2822 }
2823
2824 pub fn vertices_with_formulas(&self) -> impl Iterator<Item = VertexId> + '_ {
2826 self.vertex_formulas.keys().copied()
2827 }
2828
2829 pub fn update_vertex_formula(&mut self, id: VertexId, ast: ASTNode) -> Result<(), ExcelError> {
2831 let sheet_id = self.store.sheet_id(id);
2833
2834 let has_ref_marker = ast.get_dependencies().into_iter().any(|r| {
2838 matches!(
2839 r,
2840 ReferenceType::Cell { sheet: Some(s), .. }
2841 | ReferenceType::Range { sheet: Some(s), .. } if s == "#REF"
2842 )
2843 });
2844 if has_ref_marker {
2845 let ast_id = self.data_store.store_ast(&ast, &self.sheet_reg);
2847 self.vertex_formulas.insert(id, ast_id);
2848 self.mark_as_ref_error(id);
2849 self.store.set_kind(id, VertexKind::FormulaScalar);
2850 return Ok(());
2851 }
2852
2853 let (new_dependencies, new_range_dependencies, _) =
2855 self.extract_dependencies(&ast, sheet_id)?;
2856
2857 self.remove_dependent_edges(id);
2859
2860 let ast_id = self.data_store.store_ast(&ast, &self.sheet_reg);
2862 self.vertex_formulas.insert(id, ast_id);
2863
2864 self.add_dependent_edges(id, &new_dependencies);
2866 self.add_range_dependent_edges(id, &new_range_dependencies, sheet_id);
2867
2868 self.store.set_kind(id, VertexKind::FormulaScalar);
2870
2871 Ok(())
2872 }
2873
2874 pub fn mark_vertex_dirty(&mut self, vertex_id: VertexId) {
2876 self.store.set_dirty(vertex_id, true);
2877 self.dirty_vertices.insert(vertex_id);
2878 }
2879
2880 pub fn update_cell_mapping(
2882 &mut self,
2883 id: VertexId,
2884 old_addr: Option<CellRef>,
2885 new_addr: CellRef,
2886 ) {
2887 if let Some(old) = old_addr {
2889 self.cell_to_vertex.remove(&old);
2890 }
2891 self.cell_to_vertex.insert(new_addr, id);
2893 }
2894
2895 pub fn remove_cell_mapping(&mut self, addr: &CellRef) {
2897 self.cell_to_vertex.remove(addr);
2898 }
2899
2900 pub fn get_cell_ref_for_vertex(&self, id: VertexId) -> Option<CellRef> {
2902 let coord = self.store.coord(id);
2903 let sheet_id = self.store.sheet_id(id);
2904 let cell_ref = CellRef::new(sheet_id, Coord::new(coord.row(), coord.col(), true, true));
2906 if self.cell_to_vertex.get(&cell_ref) == Some(&id) {
2908 Some(cell_ref)
2909 } else {
2910 None
2911 }
2912 }
2913
2914 pub fn adjust_named_ranges(
2918 &mut self,
2919 operation: &crate::engine::graph::editor::reference_adjuster::ShiftOperation,
2920 ) -> Result<(), ExcelError> {
2921 let adjuster = crate::engine::graph::editor::reference_adjuster::ReferenceAdjuster::new();
2922
2923 for named_range in self.named_ranges.values_mut() {
2925 adjust_named_definition(&mut named_range.definition, &adjuster, operation)?;
2926 }
2927
2928 for named_range in self.sheet_named_ranges.values_mut() {
2930 adjust_named_definition(&mut named_range.definition, &adjuster, operation)?;
2931 }
2932
2933 Ok(())
2934 }
2935
2936 pub fn mark_as_name_error(&mut self, vertex_id: VertexId) {
2938 self.mark_vertex_dirty(vertex_id);
2940 }
2943}
2944
2945impl DependencyGraph {
2950 pub fn add_sheet(&mut self, name: &str) -> Result<SheetId, ExcelError> {
2961 if let Some(id) = self.sheet_reg.get_id(name) {
2963 return Ok(id);
2965 }
2966
2967 let sheet_id = self.sheet_reg.id_for(name);
2969
2970 self.sheet_indexes.entry(sheet_id).or_default();
2972
2973 Ok(sheet_id)
2974 }
2975
2976 pub fn remove_sheet(&mut self, sheet_id: SheetId) -> Result<(), ExcelError> {
2992 if self.sheet_reg.name(sheet_id).is_empty() {
2994 return Err(ExcelError::new(ExcelErrorKind::Value).with_message("Sheet does not exist"));
2995 }
2996
2997 let sheet_count = self.sheet_reg.all_sheets().len();
2999 if sheet_count <= 1 {
3000 return Err(
3001 ExcelError::new(ExcelErrorKind::Value).with_message("Cannot remove the last sheet")
3002 );
3003 }
3004
3005 self.begin_batch();
3007
3008 let vertices_to_delete: Vec<VertexId> = self.vertices_in_sheet(sheet_id).collect();
3010
3011 let mut formulas_to_update = Vec::new();
3013 for &formula_id in self.vertex_formulas.keys() {
3014 let deps = self.edges.out_edges(formula_id);
3015 for dep_id in deps {
3016 if self.store.sheet_id(dep_id) == sheet_id {
3017 formulas_to_update.push(formula_id);
3018 break;
3019 }
3020 }
3021 }
3022
3023 for formula_id in formulas_to_update {
3025 self.mark_as_ref_error(formula_id);
3026 }
3027
3028 for vertex_id in vertices_to_delete {
3030 if let Some(cell_ref) = self.get_cell_ref_for_vertex(vertex_id) {
3032 self.cell_to_vertex.remove(&cell_ref);
3033 }
3034
3035 self.remove_all_edges(vertex_id);
3037
3038 let coord = self.store.coord(vertex_id);
3040 if let Some(index) = self.sheet_indexes.get_mut(&sheet_id) {
3041 index.remove_vertex(coord, vertex_id);
3042 }
3043
3044 self.vertex_formulas.remove(&vertex_id);
3046 self.vertex_values.remove(&vertex_id);
3047
3048 self.mark_deleted(vertex_id, true);
3050 }
3051
3052 let sheet_names_to_remove: Vec<(SheetId, String)> = self
3054 .sheet_named_ranges
3055 .keys()
3056 .filter(|(sid, _)| *sid == sheet_id)
3057 .cloned()
3058 .collect();
3059
3060 for key in sheet_names_to_remove {
3061 self.sheet_named_ranges.remove(&key);
3062 }
3063
3064 self.sheet_indexes.remove(&sheet_id);
3066
3067 if self.default_sheet_id == sheet_id {
3069 if let Some(&new_default) = self.sheet_indexes.keys().next() {
3071 self.default_sheet_id = new_default;
3072 }
3073 }
3074
3075 self.sheet_reg.remove(sheet_id)?;
3077
3078 self.end_batch();
3080
3081 Ok(())
3082 }
3083
3084 pub fn rename_sheet(&mut self, sheet_id: SheetId, new_name: &str) -> Result<(), ExcelError> {
3099 if new_name.is_empty() || new_name.len() > 255 {
3101 return Err(ExcelError::new(ExcelErrorKind::Value).with_message("Invalid sheet name"));
3102 }
3103
3104 let old_name = self.sheet_reg.name(sheet_id);
3106 if old_name.is_empty() {
3107 return Err(ExcelError::new(ExcelErrorKind::Value).with_message("Sheet does not exist"));
3108 }
3109
3110 if let Some(existing_id) = self.sheet_reg.get_id(new_name) {
3112 if existing_id != sheet_id {
3113 return Err(ExcelError::new(ExcelErrorKind::Value)
3114 .with_message(format!("Sheet '{new_name}' already exists")));
3115 }
3116 return Ok(());
3118 }
3119
3120 let old_name = old_name.to_string();
3122
3123 self.sheet_reg.rename(sheet_id, new_name)?;
3125
3126 let formulas_to_update: Vec<VertexId> = self.vertex_formulas.keys().copied().collect();
3129
3130 for formula_id in formulas_to_update {
3131 if let Some(ast) = self.get_formula(formula_id) {
3132 let updated_ast = update_sheet_references_in_ast(&ast, &old_name, new_name);
3133 if ast != updated_ast {
3134 let ast_id = self.data_store.store_ast(&updated_ast, &self.sheet_reg);
3136 self.vertex_formulas.insert(formula_id, ast_id);
3137 self.mark_vertex_dirty(formula_id);
3138 }
3139 }
3140 }
3141
3142 Ok(())
3143 }
3144
3145 pub fn duplicate_sheet(
3165 &mut self,
3166 source_sheet_id: SheetId,
3167 new_name: &str,
3168 ) -> Result<SheetId, ExcelError> {
3169 if new_name.is_empty() || new_name.len() > 255 {
3171 return Err(ExcelError::new(ExcelErrorKind::Value).with_message("Invalid sheet name"));
3172 }
3173
3174 let source_name = self.sheet_reg.name(source_sheet_id).to_string();
3176 if source_name.is_empty() {
3177 return Err(
3178 ExcelError::new(ExcelErrorKind::Value).with_message("Source sheet does not exist")
3179 );
3180 }
3181
3182 if self.sheet_reg.get_id(new_name).is_some() {
3184 return Err(ExcelError::new(ExcelErrorKind::Value)
3185 .with_message(format!("Sheet '{new_name}' already exists")));
3186 }
3187
3188 let new_sheet_id = self.add_sheet(new_name)?;
3190
3191 self.begin_batch();
3193
3194 let source_vertices: Vec<(VertexId, PackedCoord)> = self
3196 .vertices_in_sheet(source_sheet_id)
3197 .map(|id| (id, self.store.coord(id)))
3198 .collect();
3199
3200 let mut vertex_mapping = FxHashMap::default();
3202
3203 for (old_id, coord) in &source_vertices {
3205 let row = coord.row();
3206 let col = coord.col();
3207 let kind = self.store.kind(*old_id);
3208
3209 let new_id = self.store.allocate(*coord, new_sheet_id, 0x01); self.edges.add_vertex(*coord, new_id.0);
3214
3215 self.sheet_index_mut(new_sheet_id)
3217 .add_vertex(*coord, new_id);
3218
3219 self.store.set_kind(new_id, kind);
3221
3222 if let Some(&value_ref) = self.vertex_values.get(old_id) {
3224 self.vertex_values.insert(new_id, value_ref);
3225 }
3226
3227 vertex_mapping.insert(*old_id, new_id);
3229
3230 let cell_ref = CellRef::new(new_sheet_id, Coord::new(row, col, true, true));
3232 self.cell_to_vertex.insert(cell_ref, new_id);
3233 }
3234
3235 for (old_id, _) in &source_vertices {
3237 if let Some(&new_id) = vertex_mapping.get(old_id) {
3238 if let Some(&ast_id) = self.vertex_formulas.get(old_id) {
3239 if let Some(ast) = self.data_store.retrieve_ast(ast_id, &self.sheet_reg) {
3240 let updated_ast = update_internal_sheet_references(
3242 &ast,
3243 &source_name,
3244 new_name,
3245 source_sheet_id,
3246 new_sheet_id,
3247 );
3248
3249 let new_ast_id = self.data_store.store_ast(&updated_ast, &self.sheet_reg);
3251 self.vertex_formulas.insert(new_id, new_ast_id);
3252
3253 if let Ok((deps, range_deps, _)) =
3255 self.extract_dependencies(&updated_ast, new_sheet_id)
3256 {
3257 let mapped_deps: Vec<VertexId> = deps
3259 .iter()
3260 .map(|&dep_id| {
3261 vertex_mapping.get(&dep_id).copied().unwrap_or(dep_id)
3263 })
3264 .collect();
3265
3266 self.add_dependent_edges(new_id, &mapped_deps);
3267 self.add_range_dependent_edges(new_id, &range_deps, new_sheet_id);
3268 }
3269 }
3270 }
3271 }
3272 }
3273
3274 let sheet_names: Vec<(String, NamedRange)> = self
3276 .sheet_named_ranges
3277 .iter()
3278 .filter(|((sid, _), _)| *sid == source_sheet_id)
3279 .map(|((_, name), range)| (name.clone(), range.clone()))
3280 .collect();
3281
3282 for (name, mut named_range) in sheet_names {
3283 named_range.scope = NameScope::Sheet(new_sheet_id);
3285
3286 match &mut named_range.definition {
3288 NamedDefinition::Cell(cell_ref) if cell_ref.sheet_id == source_sheet_id => {
3289 cell_ref.sheet_id = new_sheet_id;
3290 }
3291 NamedDefinition::Range(range_ref) => {
3292 if range_ref.start.sheet_id == source_sheet_id {
3293 range_ref.start.sheet_id = new_sheet_id;
3294 range_ref.end.sheet_id = new_sheet_id;
3295 }
3296 }
3297 _ => {}
3298 }
3299
3300 self.sheet_named_ranges
3301 .insert((new_sheet_id, name), named_range);
3302 }
3303
3304 self.end_batch();
3306
3307 Ok(new_sheet_id)
3308 }
3309}
3310
3311fn update_sheet_references_in_ast(ast: &ASTNode, old_name: &str, new_name: &str) -> ASTNode {
3313 match &ast.node_type {
3314 ASTNodeType::Reference { reference, .. } => {
3315 let updated_ref = match reference {
3316 ReferenceType::Cell { sheet, row, col } => {
3317 if sheet.as_deref() == Some(old_name) {
3318 ReferenceType::Cell {
3319 sheet: Some(new_name.to_string()),
3320 row: *row,
3321 col: *col,
3322 }
3323 } else {
3324 reference.clone()
3325 }
3326 }
3327 ReferenceType::Range {
3328 sheet,
3329 start_row,
3330 start_col,
3331 end_row,
3332 end_col,
3333 } => {
3334 if sheet.as_deref() == Some(old_name) {
3335 ReferenceType::Range {
3336 sheet: Some(new_name.to_string()),
3337 start_row: *start_row,
3338 start_col: *start_col,
3339 end_row: *end_row,
3340 end_col: *end_col,
3341 }
3342 } else {
3343 reference.clone()
3344 }
3345 }
3346 _ => reference.clone(),
3347 };
3348
3349 ASTNode {
3350 node_type: ASTNodeType::Reference {
3351 original: String::new(),
3352 reference: updated_ref,
3353 },
3354 source_token: None,
3355 contains_volatile: ast.contains_volatile,
3356 }
3357 }
3358 ASTNodeType::BinaryOp { op, left, right } => ASTNode {
3359 node_type: ASTNodeType::BinaryOp {
3360 op: op.clone(),
3361 left: Box::new(update_sheet_references_in_ast(left, old_name, new_name)),
3362 right: Box::new(update_sheet_references_in_ast(right, old_name, new_name)),
3363 },
3364 source_token: None,
3365 contains_volatile: ast.contains_volatile,
3366 },
3367 ASTNodeType::UnaryOp { op, expr } => ASTNode {
3368 node_type: ASTNodeType::UnaryOp {
3369 op: op.clone(),
3370 expr: Box::new(update_sheet_references_in_ast(expr, old_name, new_name)),
3371 },
3372 source_token: None,
3373 contains_volatile: ast.contains_volatile,
3374 },
3375 ASTNodeType::Function { name, args } => ASTNode {
3376 node_type: ASTNodeType::Function {
3377 name: name.clone(),
3378 args: args
3379 .iter()
3380 .map(|arg| update_sheet_references_in_ast(arg, old_name, new_name))
3381 .collect(),
3382 },
3383 source_token: None,
3384 contains_volatile: ast.contains_volatile,
3385 },
3386 ASTNodeType::Array(rows) => ASTNode {
3387 node_type: ASTNodeType::Array(
3388 rows.iter()
3389 .map(|row| {
3390 row.iter()
3391 .map(|cell| update_sheet_references_in_ast(cell, old_name, new_name))
3392 .collect()
3393 })
3394 .collect(),
3395 ),
3396 source_token: None,
3397 contains_volatile: ast.contains_volatile,
3398 },
3399 _ => ast.clone(),
3400 }
3401}
3402
3403fn update_internal_sheet_references(
3405 ast: &ASTNode,
3406 source_name: &str,
3407 new_name: &str,
3408 source_id: SheetId,
3409 new_id: SheetId,
3410) -> ASTNode {
3411 match &ast.node_type {
3412 ASTNodeType::Reference { reference, .. } => {
3413 let updated_ref = match reference {
3414 ReferenceType::Cell { sheet, row, col } => {
3415 if sheet.is_none() || sheet.as_deref() == Some(source_name) {
3417 ReferenceType::Cell {
3418 sheet: Some(new_name.to_string()),
3419 row: *row,
3420 col: *col,
3421 }
3422 } else {
3423 reference.clone()
3424 }
3425 }
3426 ReferenceType::Range {
3427 sheet,
3428 start_row,
3429 start_col,
3430 end_row,
3431 end_col,
3432 } => {
3433 if sheet.is_none() || sheet.as_deref() == Some(source_name) {
3434 ReferenceType::Range {
3435 sheet: Some(new_name.to_string()),
3436 start_row: *start_row,
3437 start_col: *start_col,
3438 end_row: *end_row,
3439 end_col: *end_col,
3440 }
3441 } else {
3442 reference.clone()
3443 }
3444 }
3445 _ => reference.clone(),
3446 };
3447
3448 ASTNode {
3449 node_type: ASTNodeType::Reference {
3450 original: String::new(),
3451 reference: updated_ref,
3452 },
3453 source_token: None,
3454 contains_volatile: ast.contains_volatile,
3455 }
3456 }
3457 ASTNodeType::BinaryOp { op, left, right } => ASTNode {
3458 node_type: ASTNodeType::BinaryOp {
3459 op: op.clone(),
3460 left: Box::new(update_internal_sheet_references(
3461 left,
3462 source_name,
3463 new_name,
3464 source_id,
3465 new_id,
3466 )),
3467 right: Box::new(update_internal_sheet_references(
3468 right,
3469 source_name,
3470 new_name,
3471 source_id,
3472 new_id,
3473 )),
3474 },
3475 source_token: None,
3476 contains_volatile: ast.contains_volatile,
3477 },
3478 ASTNodeType::UnaryOp { op, expr } => ASTNode {
3479 node_type: ASTNodeType::UnaryOp {
3480 op: op.clone(),
3481 expr: Box::new(update_internal_sheet_references(
3482 expr,
3483 source_name,
3484 new_name,
3485 source_id,
3486 new_id,
3487 )),
3488 },
3489 source_token: None,
3490 contains_volatile: ast.contains_volatile,
3491 },
3492 ASTNodeType::Function { name, args } => ASTNode {
3493 node_type: ASTNodeType::Function {
3494 name: name.clone(),
3495 args: args
3496 .iter()
3497 .map(|arg| {
3498 update_internal_sheet_references(
3499 arg,
3500 source_name,
3501 new_name,
3502 source_id,
3503 new_id,
3504 )
3505 })
3506 .collect(),
3507 },
3508 source_token: None,
3509 contains_volatile: ast.contains_volatile,
3510 },
3511 ASTNodeType::Array(rows) => ASTNode {
3512 node_type: ASTNodeType::Array(
3513 rows.iter()
3514 .map(|row| {
3515 row.iter()
3516 .map(|cell| {
3517 update_internal_sheet_references(
3518 cell,
3519 source_name,
3520 new_name,
3521 source_id,
3522 new_id,
3523 )
3524 })
3525 .collect()
3526 })
3527 .collect(),
3528 ),
3529 source_token: None,
3530 contains_volatile: ast.contains_volatile,
3531 },
3532 _ => ast.clone(),
3533 }
3534}
3535
3536fn adjust_named_definition(
3538 definition: &mut NamedDefinition,
3539 adjuster: &crate::engine::graph::editor::reference_adjuster::ReferenceAdjuster,
3540 operation: &crate::engine::graph::editor::reference_adjuster::ShiftOperation,
3541) -> Result<(), ExcelError> {
3542 match definition {
3543 NamedDefinition::Cell(cell_ref) => {
3544 if let Some(adjusted) = adjuster.adjust_cell_ref(cell_ref, operation) {
3545 *cell_ref = adjusted;
3546 } else {
3547 return Err(ExcelError::new(ExcelErrorKind::Ref));
3549 }
3550 }
3551 NamedDefinition::Range(range_ref) => {
3552 let adjusted_start = adjuster.adjust_cell_ref(&range_ref.start, operation);
3553 let adjusted_end = adjuster.adjust_cell_ref(&range_ref.end, operation);
3554
3555 if let (Some(start), Some(end)) = (adjusted_start, adjusted_end) {
3556 range_ref.start = start;
3557 range_ref.end = end;
3558 } else {
3559 return Err(ExcelError::new(ExcelErrorKind::Ref));
3560 }
3561 }
3562 NamedDefinition::Formula {
3563 ast,
3564 dependencies,
3565 range_deps,
3566 } => {
3567 let adjusted_ast = adjuster.adjust_ast(ast, operation);
3569 *ast = adjusted_ast;
3570
3571 dependencies.clear();
3573 range_deps.clear();
3574 }
3575 }
3576 Ok(())
3577}