1use crate::error::IoError;
2use crate::loader::WorkbookLoader;
3use crate::traits::{LoadStrategy, SpreadsheetReader, SpreadsheetWriter};
4use chrono::Timelike;
5use formualizer_common::{
6 LiteralValue, RangeAddress,
7 error::{ExcelError, ExcelErrorKind},
8};
9use formualizer_eval::engine::named_range::NamedDefinition;
10use std::cell::Cell;
11use std::collections::BTreeMap;
12use std::ptr;
13
14thread_local! {
15 static ACTIVE_WORKBOOK: Cell<*const Workbook> = const { Cell::new(ptr::null()) };
16}
17
18#[derive(Default, Debug, Clone, Copy)]
20pub struct WBResolver;
21
22impl formualizer_eval::traits::ReferenceResolver for WBResolver {
23 fn resolve_cell_reference(
24 &self,
25 _sheet: Option<&str>,
26 _row: u32,
27 _col: u32,
28 ) -> Result<LiteralValue, formualizer_common::error::ExcelError> {
29 Err(formualizer_common::error::ExcelError::from(
30 formualizer_common::error::ExcelErrorKind::NImpl,
31 ))
32 }
33}
34impl formualizer_eval::traits::RangeResolver for WBResolver {
35 fn resolve_range_reference(
36 &self,
37 _sheet: Option<&str>,
38 _sr: Option<u32>,
39 _sc: Option<u32>,
40 _er: Option<u32>,
41 _ec: Option<u32>,
42 ) -> Result<Box<dyn formualizer_eval::traits::Range>, formualizer_common::error::ExcelError>
43 {
44 Err(formualizer_common::error::ExcelError::from(
45 formualizer_common::error::ExcelErrorKind::NImpl,
46 ))
47 }
48}
49impl formualizer_eval::traits::NamedRangeResolver for WBResolver {
50 fn resolve_named_range_reference(
51 &self,
52 _name: &str,
53 ) -> Result<Vec<Vec<LiteralValue>>, formualizer_common::error::ExcelError> {
54 ACTIVE_WORKBOOK.with(|cell| {
55 let ptr = cell.get();
56 if ptr.is_null() {
57 return Err(ExcelError::new(ExcelErrorKind::Name));
58 }
59 let workbook = unsafe { &*ptr };
60 if let Some(addr) = workbook.named_range_address(_name) {
61 Ok(workbook.read_range(&addr))
62 } else {
63 Err(ExcelError::new(ExcelErrorKind::Name))
64 }
65 })
66 }
67}
68impl formualizer_eval::traits::TableResolver for WBResolver {
69 fn resolve_table_reference(
70 &self,
71 _tref: &formualizer_parse::parser::TableReference,
72 ) -> Result<Box<dyn formualizer_eval::traits::Table>, formualizer_common::error::ExcelError>
73 {
74 Err(formualizer_common::error::ExcelError::from(
75 formualizer_common::error::ExcelErrorKind::NImpl,
76 ))
77 }
78}
79impl formualizer_eval::traits::FunctionProvider for WBResolver {
80 fn get_function(
81 &self,
82 ns: &str,
83 name: &str,
84 ) -> Option<std::sync::Arc<dyn formualizer_eval::function::Function>> {
85 formualizer_eval::function_registry::get(ns, name)
86 }
87}
88impl formualizer_eval::traits::Resolver for WBResolver {}
89impl formualizer_eval::traits::EvaluationContext for WBResolver {}
90
91pub struct Workbook {
93 engine: formualizer_eval::engine::Engine<WBResolver>,
94 enable_changelog: bool,
95 log: formualizer_eval::engine::ChangeLog,
96 undo: formualizer_eval::engine::graph::editor::undo_engine::UndoEngine,
97}
98
99impl Default for Workbook {
100 fn default() -> Self {
101 Self::new()
102 }
103}
104
105impl Workbook {
106 pub fn new_with_config(config: formualizer_eval::engine::EvalConfig) -> Self {
107 let engine = formualizer_eval::engine::Engine::new(WBResolver, config);
108 Self {
109 engine,
110 enable_changelog: false,
111 log: formualizer_eval::engine::ChangeLog::new(),
112 undo: formualizer_eval::engine::graph::editor::undo_engine::UndoEngine::new(),
113 }
114 }
115 pub fn new() -> Self {
116 let cfg = formualizer_eval::engine::EvalConfig {
117 defer_graph_building: true,
118 ..Default::default()
119 };
120 Self::new_with_config(cfg)
121 }
122
123 pub fn engine(&self) -> &formualizer_eval::engine::Engine<WBResolver> {
124 &self.engine
125 }
126 pub fn engine_mut(&mut self) -> &mut formualizer_eval::engine::Engine<WBResolver> {
127 &mut self.engine
128 }
129
130 pub fn set_changelog_enabled(&mut self, enabled: bool) {
132 self.enable_changelog = enabled;
133 self.log.set_enabled(enabled);
134 }
135 pub fn begin_action(&mut self, description: impl Into<String>) {
136 if self.enable_changelog {
137 self.log.begin_compound(description.into());
138 }
139 }
140 pub fn end_action(&mut self) {
141 if self.enable_changelog {
142 self.log.end_compound();
143 }
144 }
145 pub fn undo(&mut self) -> Result<(), IoError> {
146 if self.enable_changelog {
147 self.undo
148 .undo(&mut self.engine.graph, &mut self.log)
149 .map_err(|e| IoError::from_backend("editor", e))?;
150 self.resync_all_overlays();
151 }
152 Ok(())
153 }
154 pub fn redo(&mut self) -> Result<(), IoError> {
155 if self.enable_changelog {
156 self.undo
157 .redo(&mut self.engine.graph, &mut self.log)
158 .map_err(|e| IoError::from_backend("editor", e))?;
159 self.resync_all_overlays();
160 }
161 Ok(())
162 }
163
164 fn resync_all_overlays(&mut self) {
165 let sheet_names: Vec<String> = self
167 .engine
168 .sheet_store()
169 .sheets
170 .iter()
171 .map(|s| s.name.as_ref().to_string())
172 .collect();
173 for s in sheet_names {
174 self.resync_overlay_for_sheet(&s);
175 }
176 }
177 fn resync_overlay_for_sheet(&mut self, sheet: &str) {
178 if let Some(asheet) = self.engine.sheet_store().sheet(sheet) {
179 let rows = asheet.nrows as usize;
180 let cols = asheet.columns.len();
181 for r0 in 0..rows {
182 let r = (r0 as u32) + 1;
183 for c0 in 0..cols {
184 let c = (c0 as u32) + 1;
185 let v = self
186 .engine
187 .graph
188 .get_cell_value(sheet, r, c)
189 .unwrap_or(LiteralValue::Empty);
190 self.mirror_value_to_overlay(sheet, r, c, &v);
191 }
192 }
193 }
194 }
196 fn mirror_value_to_overlay(&mut self, sheet: &str, row: u32, col: u32, value: &LiteralValue) {
197 use formualizer_eval::arrow_store::OverlayValue;
198 if !(self.engine.config.arrow_storage_enabled && self.engine.config.delta_overlay_enabled) {
199 return;
200 }
201 let date_system = self.engine.config.date_system;
202 let asheet = match self.engine.sheet_store_mut().sheet_mut(sheet) {
203 Some(s) => s,
204 None => return,
205 };
206 let row0 = row.saturating_sub(1) as usize;
207 let col0 = col.saturating_sub(1) as usize;
208 if col0 >= asheet.columns.len() {
209 return;
210 }
211 if row0 >= asheet.nrows as usize {
212 asheet.ensure_row_capacity(row0 + 1);
213 }
214 if let Some((ch_idx, in_off)) = asheet.chunk_of_row(row0) {
215 let ov = match value {
216 LiteralValue::Empty => OverlayValue::Empty,
217 LiteralValue::Int(i) => OverlayValue::Number(*i as f64),
218 LiteralValue::Number(n) => OverlayValue::Number(*n),
219 LiteralValue::Boolean(b) => OverlayValue::Boolean(*b),
220 LiteralValue::Text(s) => OverlayValue::Text(std::sync::Arc::from(s.clone())),
221 LiteralValue::Error(e) => {
222 OverlayValue::Error(formualizer_eval::arrow_store::map_error_code(e.kind))
223 }
224 LiteralValue::Date(d) => {
225 let dt = d.and_hms_opt(0, 0, 0).unwrap();
226 let serial = formualizer_eval::builtins::datetime::datetime_to_serial_for(
227 date_system,
228 &dt,
229 );
230 OverlayValue::Number(serial)
231 }
232 LiteralValue::DateTime(dt) => {
233 let serial = formualizer_eval::builtins::datetime::datetime_to_serial_for(
234 date_system,
235 dt,
236 );
237 OverlayValue::Number(serial)
238 }
239 LiteralValue::Time(t) => {
240 let serial = t.num_seconds_from_midnight() as f64 / 86_400.0;
241 OverlayValue::Number(serial)
242 }
243 LiteralValue::Duration(d) => {
244 let serial = d.num_seconds() as f64 / 86_400.0;
245 OverlayValue::Number(serial)
246 }
247 LiteralValue::Pending => OverlayValue::Pending,
248 LiteralValue::Array(_) => {
249 OverlayValue::Error(formualizer_eval::arrow_store::map_error_code(
250 formualizer_common::ExcelErrorKind::Value,
251 ))
252 }
253 };
254 let colref = &mut asheet.columns[col0];
255 let ch = &mut colref.chunks[ch_idx];
256 ch.overlay.set(in_off, ov);
257 }
259 }
260
261 pub fn sheet_names(&self) -> Vec<String> {
263 self.engine
264 .sheet_store()
265 .sheets
266 .iter()
267 .map(|s| s.name.as_ref().to_string())
268 .collect()
269 }
270 pub fn sheet_dimensions(&self, name: &str) -> Option<(u32, u32)> {
272 self.engine
273 .sheet_store()
274 .sheet(name)
275 .map(|s| (s.nrows, s.columns.len() as u32))
276 }
277 pub fn has_sheet(&self, name: &str) -> bool {
278 self.engine.graph.sheet_id(name).is_some()
279 }
280 pub fn add_sheet(&mut self, name: &str) {
281 let _ = self.engine.graph.add_sheet(name);
282 }
283 pub fn delete_sheet(&mut self, name: &str) {
284 if let Some(id) = self.engine.graph.sheet_id(name) {
285 let _ = self.engine.graph.remove_sheet(id);
286 }
287 self.engine
289 .sheet_store_mut()
290 .sheets
291 .retain(|s| s.name.as_ref() != name);
292 }
293 pub fn rename_sheet(&mut self, old: &str, new: &str) {
294 if let Some(id) = self.engine.graph.sheet_id(old) {
295 let _ = self.engine.graph.rename_sheet(id, new);
296 }
297 if let Some(asheet) = self.engine.sheet_store_mut().sheet_mut(old) {
298 asheet.name = std::sync::Arc::<str>::from(new);
299 }
300 }
301
302 pub fn set_value(
304 &mut self,
305 sheet: &str,
306 row: u32,
307 col: u32,
308 value: LiteralValue,
309 ) -> Result<(), IoError> {
310 if self.enable_changelog {
311 let sheet_id = self
313 .engine
314 .graph
315 .sheet_id(sheet)
316 .unwrap_or_else(|| self.engine.graph.add_sheet(sheet).unwrap());
317 let cell = formualizer_eval::reference::CellRef::new(
318 sheet_id,
319 formualizer_eval::reference::Coord::from_excel(row, col, true, true),
320 );
321 {
322 let mut editor = formualizer_eval::engine::VertexEditor::with_logger(
323 &mut self.engine.graph,
324 &mut self.log,
325 );
326 editor.set_cell_value(cell, value.clone());
327 }
328 self.mirror_value_to_overlay(sheet, row, col, &value);
329 self.engine.mark_data_edited();
330 Ok(())
331 } else {
332 self.engine
333 .set_cell_value(sheet, row, col, value)
334 .map_err(IoError::Engine)
335 }
336 }
337 pub fn set_formula(
338 &mut self,
339 sheet: &str,
340 row: u32,
341 col: u32,
342 formula: &str,
343 ) -> Result<(), IoError> {
344 if self.engine.config.defer_graph_building {
345 self.engine
346 .stage_formula_text(sheet, row, col, formula.to_string());
347 Ok(())
348 } else {
349 let with_eq = if formula.starts_with('=') {
350 formula.to_string()
351 } else {
352 format!("={formula}")
353 };
354 let ast = formualizer_parse::parser::parse(&with_eq)
355 .map_err(|e| IoError::from_backend("parser", e))?;
356 if self.enable_changelog {
357 let sheet_id = self
358 .engine
359 .graph
360 .sheet_id(sheet)
361 .unwrap_or_else(|| self.engine.graph.add_sheet(sheet).unwrap());
362 let cell = formualizer_eval::reference::CellRef::new(
363 sheet_id,
364 formualizer_eval::reference::Coord::from_excel(row, col, true, true),
365 );
366 {
367 let mut editor = formualizer_eval::engine::VertexEditor::with_logger(
368 &mut self.engine.graph,
369 &mut self.log,
370 );
371 editor.set_cell_formula(cell, ast);
372 }
373 self.engine.mark_data_edited();
374 Ok(())
375 } else {
376 self.engine
377 .set_cell_formula(sheet, row, col, ast)
378 .map_err(IoError::Engine)
379 }
380 }
381 }
382 pub fn get_value(&self, sheet: &str, row: u32, col: u32) -> Option<LiteralValue> {
383 self.engine.get_cell_value(sheet, row, col)
384 }
385 pub fn get_formula(&self, sheet: &str, row: u32, col: u32) -> Option<String> {
386 if let Some(s) = self.engine.get_staged_formula_text(sheet, row, col) {
387 return Some(s);
388 }
389 self.engine
390 .get_cell(sheet, row, col)
391 .and_then(|(ast, _)| ast.map(|a| formualizer_parse::pretty::canonical_formula(&a)))
392 }
393
394 pub fn read_range(&self, addr: &RangeAddress) -> Vec<Vec<LiteralValue>> {
396 let mut out = Vec::with_capacity(addr.height() as usize);
397 if let Some(asheet) = self.engine.sheet_store().sheet(&addr.sheet) {
398 let sr0 = addr.start_row.saturating_sub(1) as usize;
399 let sc0 = addr.start_col.saturating_sub(1) as usize;
400 let er0 = addr.end_row.saturating_sub(1) as usize;
401 let ec0 = addr.end_col.saturating_sub(1) as usize;
402 let view = asheet.range_view(sr0, sc0, er0, ec0);
403 let (h, w) = view.dims();
404 for rr in 0..h {
405 let mut row = Vec::with_capacity(w);
406 for cc in 0..w {
407 row.push(view.get_cell(rr, cc));
408 }
409 out.push(row);
410 }
411 } else {
412 for r in addr.start_row..=addr.end_row {
414 let mut row = Vec::with_capacity(addr.width() as usize);
415 for c in addr.start_col..=addr.end_col {
416 row.push(
417 self.engine
418 .graph
419 .get_cell_value(&addr.sheet, r, c)
420 .unwrap_or(LiteralValue::Empty),
421 );
422 }
423 out.push(row);
424 }
425 }
426 out
427 }
428 pub fn write_range(
429 &mut self,
430 sheet: &str,
431 _start: (u32, u32),
432 cells: BTreeMap<(u32, u32), crate::traits::CellData>,
433 ) -> Result<(), IoError> {
434 if self.enable_changelog {
435 let sheet_id = self
436 .engine
437 .graph
438 .sheet_id(sheet)
439 .unwrap_or_else(|| self.engine.graph.add_sheet(sheet).unwrap());
440 let mut overlay_ops: Vec<(u32, u32, LiteralValue)> = Vec::new();
441 let mut staged_forms: Vec<(u32, u32, String)> = Vec::new();
442 {
443 let mut editor = formualizer_eval::engine::VertexEditor::with_logger(
444 &mut self.engine.graph,
445 &mut self.log,
446 );
447 for ((r, c), d) in cells.into_iter() {
448 let cell = formualizer_eval::reference::CellRef::new(
449 sheet_id,
450 formualizer_eval::reference::Coord::from_excel(r, c, true, true),
451 );
452 if let Some(v) = d.value.clone() {
453 editor.set_cell_value(cell, v.clone());
454 overlay_ops.push((r, c, v));
455 }
456 if let Some(f) = d.formula.as_ref() {
457 if self.engine.config.defer_graph_building {
458 staged_forms.push((r, c, f.clone()));
459 } else {
460 let with_eq = if f.starts_with('=') {
461 f.clone()
462 } else {
463 format!("={f}")
464 };
465 let ast = formualizer_parse::parser::parse(&with_eq)
466 .map_err(|e| IoError::from_backend("parser", e))?;
467 editor.set_cell_formula(cell, ast);
468 }
469 }
470 }
471 }
472 for (r, c, v) in overlay_ops {
473 self.mirror_value_to_overlay(sheet, r, c, &v);
474 }
475 for (r, c, f) in staged_forms {
476 self.engine.stage_formula_text(sheet, r, c, f);
477 }
478 self.engine.mark_data_edited();
479 Ok(())
480 } else {
481 for ((r, c), d) in cells.into_iter() {
482 if let Some(v) = d.value.clone() {
483 self.engine
484 .set_cell_value(sheet, r, c, v)
485 .map_err(IoError::Engine)?;
486 }
487 if let Some(f) = d.formula.as_ref() {
488 if self.engine.config.defer_graph_building {
489 self.engine.stage_formula_text(sheet, r, c, f.clone());
490 } else {
491 let with_eq = if f.starts_with('=') {
492 f.clone()
493 } else {
494 format!("={f}")
495 };
496 let ast = formualizer_parse::parser::parse(&with_eq)
497 .map_err(|e| IoError::from_backend("parser", e))?;
498 self.engine
499 .set_cell_formula(sheet, r, c, ast)
500 .map_err(IoError::Engine)?;
501 }
502 }
503 }
504 Ok(())
505 }
506 }
507
508 pub fn set_values(
510 &mut self,
511 sheet: &str,
512 start_row: u32,
513 start_col: u32,
514 rows: &[Vec<LiteralValue>],
515 ) -> Result<(), IoError> {
516 if self.enable_changelog {
517 let sheet_id = self
518 .engine
519 .graph
520 .sheet_id(sheet)
521 .unwrap_or_else(|| self.engine.graph.add_sheet(sheet).unwrap());
522 let mut overlay_ops: Vec<(u32, u32, LiteralValue)> = Vec::new();
523 {
524 let mut editor = formualizer_eval::engine::VertexEditor::with_logger(
525 &mut self.engine.graph,
526 &mut self.log,
527 );
528 for (ri, rvals) in rows.iter().enumerate() {
529 let r = start_row + ri as u32;
530 for (ci, v) in rvals.iter().enumerate() {
531 let c = start_col + ci as u32;
532 let cell = formualizer_eval::reference::CellRef::new(
533 sheet_id,
534 formualizer_eval::reference::Coord::from_excel(r, c, true, true),
535 );
536 editor.set_cell_value(cell, v.clone());
537 overlay_ops.push((r, c, v.clone()));
538 }
539 }
540 }
541 for (r, c, v) in overlay_ops {
542 self.mirror_value_to_overlay(sheet, r, c, &v);
543 }
544 self.engine.mark_data_edited();
545 Ok(())
546 } else {
547 for (ri, rvals) in rows.iter().enumerate() {
548 let r = start_row + ri as u32;
549 for (ci, v) in rvals.iter().enumerate() {
550 let c = start_col + ci as u32;
551 self.engine
552 .set_cell_value(sheet, r, c, v.clone())
553 .map_err(IoError::Engine)?;
554 }
555 }
556 Ok(())
557 }
558 }
559
560 pub fn set_formulas(
562 &mut self,
563 sheet: &str,
564 start_row: u32,
565 start_col: u32,
566 rows: &[Vec<String>],
567 ) -> Result<(), IoError> {
568 if self.engine.config.defer_graph_building {
569 for (ri, rforms) in rows.iter().enumerate() {
570 let r = start_row + ri as u32;
571 for (ci, f) in rforms.iter().enumerate() {
572 let c = start_col + ci as u32;
573 self.engine.stage_formula_text(sheet, r, c, f.clone());
574 }
575 }
576 Ok(())
577 } else if self.enable_changelog {
578 let sheet_id = self
579 .engine
580 .graph
581 .sheet_id(sheet)
582 .unwrap_or_else(|| self.engine.graph.add_sheet(sheet).unwrap());
583 {
584 let mut editor = formualizer_eval::engine::VertexEditor::with_logger(
585 &mut self.engine.graph,
586 &mut self.log,
587 );
588 for (ri, rforms) in rows.iter().enumerate() {
589 let r = start_row + ri as u32;
590 for (ci, f) in rforms.iter().enumerate() {
591 let c = start_col + ci as u32;
592 let cell = formualizer_eval::reference::CellRef::new(
593 sheet_id,
594 formualizer_eval::reference::Coord::from_excel(r, c, true, true),
595 );
596 let with_eq = if f.starts_with('=') {
597 f.clone()
598 } else {
599 format!("={f}")
600 };
601 let ast = formualizer_parse::parser::parse(&with_eq)
602 .map_err(|e| IoError::from_backend("parser", e))?;
603 editor.set_cell_formula(cell, ast);
604 }
605 }
606 }
607 self.engine.mark_data_edited();
608 Ok(())
609 } else {
610 for (ri, rforms) in rows.iter().enumerate() {
611 let r = start_row + ri as u32;
612 for (ci, f) in rforms.iter().enumerate() {
613 let c = start_col + ci as u32;
614 let with_eq = if f.starts_with('=') {
615 f.clone()
616 } else {
617 format!("={f}")
618 };
619 let ast = formualizer_parse::parser::parse(&with_eq)
620 .map_err(|e| IoError::from_backend("parser", e))?;
621 self.engine
622 .set_cell_formula(sheet, r, c, ast)
623 .map_err(IoError::Engine)?;
624 }
625 }
626 Ok(())
627 }
628 }
629
630 pub fn prepare_graph_all(&mut self) -> Result<(), IoError> {
632 self.engine
633 .build_graph_all()
634 .map_err(|e| IoError::from_backend("parser", e))
635 }
636 pub fn prepare_graph_for_sheets<'a, I: IntoIterator<Item = &'a str>>(
637 &mut self,
638 sheets: I,
639 ) -> Result<(), IoError> {
640 self.engine
641 .build_graph_for_sheets(sheets)
642 .map_err(|e| IoError::from_backend("parser", e))
643 }
644 pub fn evaluate_cell(
645 &mut self,
646 sheet: &str,
647 row: u32,
648 col: u32,
649 ) -> Result<LiteralValue, IoError> {
650 ACTIVE_WORKBOOK.with(|cell| {
651 let previous = cell.replace(self as *const _);
652 let result = self
653 .engine
654 .evaluate_cell(sheet, row, col)
655 .map_err(IoError::Engine)
656 .map(|value| value.unwrap_or(LiteralValue::Empty));
657 cell.set(previous);
658 result
659 })
660 }
661 pub fn evaluate_cells(
662 &mut self,
663 targets: &[(&str, u32, u32)],
664 ) -> Result<Vec<LiteralValue>, IoError> {
665 ACTIVE_WORKBOOK.with(|cell| {
666 let previous = cell.replace(self as *const _);
667 let result = self
668 .engine
669 .evaluate_cells(targets)
670 .map_err(IoError::Engine)
671 .map(|values| {
672 values
673 .into_iter()
674 .map(|v| v.unwrap_or(LiteralValue::Empty))
675 .collect()
676 });
677 cell.set(previous);
678 result
679 })
680 }
681 pub fn evaluate_all(&mut self) -> Result<formualizer_eval::engine::EvalResult, IoError> {
682 ACTIVE_WORKBOOK.with(|cell| {
683 let previous = cell.replace(self as *const _);
684 let result = self.engine.evaluate_all().map_err(IoError::Engine);
685 cell.set(previous);
686 result
687 })
688 }
689
690 pub fn evaluate_with_plan(
691 &mut self,
692 plan: &formualizer_eval::engine::RecalcPlan,
693 ) -> Result<formualizer_eval::engine::EvalResult, IoError> {
694 ACTIVE_WORKBOOK.with(|cell| {
695 let previous = cell.replace(self as *const _);
696 let result = self
697 .engine
698 .evaluate_recalc_plan(plan)
699 .map_err(IoError::Engine);
700 cell.set(previous);
701 result
702 })
703 }
704
705 pub fn named_range_address(&self, name: &str) -> Option<RangeAddress> {
707 if let Some((_, named)) = self
708 .engine
709 .graph
710 .named_ranges_iter()
711 .find(|(n, _)| n.as_str() == name)
712 {
713 return self.named_definition_to_address(&named.definition);
714 }
715
716 let mut resolved: Option<RangeAddress> = None;
717 for ((_sheet_id, candidate), named) in self.engine.graph.sheet_named_ranges_iter() {
718 if candidate == name
719 && let Some(address) = self.named_definition_to_address(&named.definition)
720 {
721 if resolved.is_some() {
722 return None; }
724 resolved = Some(address);
725 }
726 }
727 resolved
728 }
729
730 fn named_definition_to_address(&self, definition: &NamedDefinition) -> Option<RangeAddress> {
731 match definition {
732 NamedDefinition::Cell(cell) => {
733 let sheet = self.engine.graph.sheet_name(cell.sheet_id).to_string();
734 let row = cell.coord.row() + 1;
735 let col = cell.coord.col() + 1;
736 RangeAddress::new(sheet, row, col, row, col).ok()
737 }
738 NamedDefinition::Range(range) => {
739 if range.start.sheet_id != range.end.sheet_id {
740 return None;
741 }
742 let sheet = self
743 .engine
744 .graph
745 .sheet_name(range.start.sheet_id)
746 .to_string();
747 let start_row = range.start.coord.row() + 1;
748 let start_col = range.start.coord.col() + 1;
749 let end_row = range.end.coord.row() + 1;
750 let end_col = range.end.coord.col() + 1;
751 RangeAddress::new(sheet, start_row, start_col, end_row, end_col).ok()
752 }
753 NamedDefinition::Formula { .. } => {
754 #[cfg(feature = "tracing")]
755 tracing::debug!("formula-backed named ranges are not yet supported");
756 None
757 }
758 }
759 }
760
761 pub fn begin_tx<'a, W: SpreadsheetWriter>(
763 &'a mut self,
764 writer: &'a mut W,
765 ) -> crate::transaction::WriteTransaction<'a, W> {
766 crate::transaction::WriteTransaction::new(writer)
767 }
768
769 pub fn from_reader<B: SpreadsheetReader>(
771 backend: B,
772 strategy: LoadStrategy,
773 mut config: formualizer_eval::engine::EvalConfig,
774 ) -> Result<Self, IoError> {
775 config.defer_graph_building = true;
776 let mut wb = Self::new_with_config(config);
777 let mut loader = WorkbookLoader::new(backend, strategy);
778 loader.load_into_engine(&mut wb.engine)?;
779 Ok(wb)
780 }
781}
782
783impl SpreadsheetWriter for Workbook {
785 type Error = IoError;
786
787 fn write_cell(
788 &mut self,
789 sheet: &str,
790 row: u32,
791 col: u32,
792 data: crate::traits::CellData,
793 ) -> Result<(), Self::Error> {
794 if let Some(v) = data.value {
795 self.set_value(sheet, row, col, v)?;
796 }
797 if let Some(f) = data.formula {
798 self.set_formula(sheet, row, col, &f)?;
799 }
800 Ok(())
801 }
802 fn write_range(
803 &mut self,
804 sheet: &str,
805 cells: BTreeMap<(u32, u32), crate::traits::CellData>,
806 ) -> Result<(), Self::Error> {
807 for ((r, c), d) in cells {
808 self.write_cell(sheet, r, c, d)?;
809 }
810 Ok(())
811 }
812 fn clear_range(
813 &mut self,
814 sheet: &str,
815 start: (u32, u32),
816 end: (u32, u32),
817 ) -> Result<(), Self::Error> {
818 for r in start.0..=end.0 {
819 for c in start.1..=end.1 {
820 self.set_value(sheet, r, c, LiteralValue::Empty)?;
821 }
822 }
823 Ok(())
824 }
825 fn create_sheet(&mut self, name: &str) -> Result<(), Self::Error> {
826 self.add_sheet(name);
827 Ok(())
828 }
829 fn delete_sheet(&mut self, name: &str) -> Result<(), Self::Error> {
830 self.delete_sheet(name);
831 Ok(())
832 }
833 fn rename_sheet(&mut self, old: &str, new: &str) -> Result<(), Self::Error> {
834 self.rename_sheet(old, new);
835 Ok(())
836 }
837 fn flush(&mut self) -> Result<(), Self::Error> {
838 Ok(())
839 }
840}