formualizer_workbook/
resolver.rs1use crate::traits::SpreadsheetReader;
2use formualizer_common::{
3 LiteralValue,
4 error::{ExcelError, ExcelErrorKind},
5};
6use formualizer_eval::function::Function;
7use formualizer_eval::traits::{
8 FunctionProvider, InMemoryRange, NamedRangeResolver, Range, RangeResolver, ReferenceResolver,
9 Resolver, Table, TableResolver,
10};
11use formualizer_parse::parser::TableReference;
12use parking_lot::RwLock;
13use std::sync::Arc;
14
15pub struct IoResolver<B: SpreadsheetReader> {
17 backend: RwLock<B>,
18}
19
20impl<B: SpreadsheetReader> IoResolver<B> {
21 pub fn new(backend: B) -> Self {
22 Self {
23 backend: RwLock::new(backend),
24 }
25 }
26}
27
28impl<B: SpreadsheetReader> RangeResolver for IoResolver<B> {
31 fn resolve_range_reference(
32 &self,
33 sheet: Option<&str>,
34 sr: Option<u32>,
35 sc: Option<u32>,
36 er: Option<u32>,
37 ec: Option<u32>,
38 ) -> Result<Box<dyn Range>, ExcelError> {
39 let sheet_name = sheet.ok_or_else(|| {
40 ExcelError::new(ExcelErrorKind::Ref).with_message("Missing sheet name")
41 })?;
42 let (sr, sc, er, ec) = normalize_range(sr, sc, er, ec)?;
43
44 let mut guard = self.backend.write();
46 let map = guard
47 .read_range(sheet_name, (sr, sc), (er, ec))
48 .map_err(|e| ExcelError::new(ExcelErrorKind::NImpl).with_message(e.to_string()))?;
49
50 let height = (er - sr + 1) as usize;
51 let width = (ec - sc + 1) as usize;
52 let mut rows = vec![vec![LiteralValue::Empty; width]; height];
53 for ((r, c), cell) in map.into_iter() {
54 let rr = (r - sr) as usize;
55 let cc = (c - sc) as usize;
56 if let Some(v) = cell.value {
57 rows[rr][cc] = v;
58 } else {
59 rows[rr][cc] = LiteralValue::Empty;
60 }
61 }
62 Ok(Box::new(InMemoryRange::new(rows)))
63 }
64}
65
66impl<B: SpreadsheetReader> NamedRangeResolver for IoResolver<B> {
67 fn resolve_named_range_reference(
68 &self,
69 _name: &str,
70 ) -> Result<Vec<Vec<LiteralValue>>, ExcelError> {
71 if !self.backend.read().capabilities().named_ranges {
73 return Err(ExcelError::new(ExcelErrorKind::Name)
74 .with_message("Backend doesn't support named ranges"));
75 }
76
77 Err(ExcelError::new(ExcelErrorKind::Name).with_message("Named ranges not yet implemented"))
79 }
80}
81
82impl<B: SpreadsheetReader> TableResolver for IoResolver<B> {
83 fn resolve_table_reference(
84 &self,
85 _tref: &TableReference,
86 ) -> Result<Box<dyn Table>, ExcelError> {
87 if !self.backend.read().capabilities().tables {
89 return Err(ExcelError::new(ExcelErrorKind::NImpl)
90 .with_message("Backend doesn't support tables"));
91 }
92
93 Err(ExcelError::new(ExcelErrorKind::NImpl).with_message("Tables not yet implemented"))
95 }
96}
97
98impl<B: SpreadsheetReader> FunctionProvider for IoResolver<B> {
99 fn get_function(&self, ns: &str, name: &str) -> Option<Arc<dyn Function>> {
100 formualizer_eval::function_registry::get(ns, name)
102 }
103}
104
105impl<B: SpreadsheetReader> ReferenceResolver for IoResolver<B> {
108 fn resolve_cell_reference(
109 &self,
110 _sheet: Option<&str>,
111 _row: u32,
112 _col: u32,
113 ) -> Result<LiteralValue, ExcelError> {
114 Err(ExcelError::new(ExcelErrorKind::Ref)
117 .with_message("IoResolver doesn't handle cell references"))
118 }
119}
120
121impl<B: SpreadsheetReader> Resolver for IoResolver<B> {}
122
123fn normalize_range(
124 sr: Option<u32>,
125 sc: Option<u32>,
126 er: Option<u32>,
127 ec: Option<u32>,
128) -> Result<(u32, u32, u32, u32), ExcelError> {
129 let sr = sr.unwrap_or(1);
131 let sc = sc.unwrap_or(1);
132 let er = er.unwrap_or(sr);
133 let ec = ec.unwrap_or(sc);
134
135 if sr > er || sc > ec {
137 return Err(ExcelError::new(ExcelErrorKind::Ref).with_message("Invalid range: start > end"));
138 }
139
140 Ok((sr, sc, er, ec))
141}