1use formualizer_common::{LiteralValue, RangeAddress};
2#[cfg(feature = "json")]
3use serde::{Deserialize, Serialize};
4use std::collections::BTreeMap;
5use std::io::{Read, Write};
6use std::path::Path;
7
8#[derive(Clone, Debug)]
9pub struct CellData {
10 pub value: Option<LiteralValue>,
11 pub formula: Option<String>,
12 pub style: Option<StyleId>,
13}
14
15impl CellData {
16 pub fn from_value<V: IntoLiteral>(value: V) -> Self {
17 Self {
18 value: Some(value.into_literal()),
19 formula: None,
20 style: None,
21 }
22 }
23
24 pub fn from_formula(formula: impl Into<String>) -> Self {
25 Self {
26 value: None,
27 formula: Some(formula.into()),
28 style: None,
29 }
30 }
31}
32
33pub trait IntoLiteral {
35 fn into_literal(self) -> LiteralValue;
36}
37
38impl IntoLiteral for LiteralValue {
39 fn into_literal(self) -> LiteralValue {
40 self
41 }
42}
43
44impl IntoLiteral for f64 {
45 fn into_literal(self) -> LiteralValue {
46 LiteralValue::Number(self)
47 }
48}
49
50impl IntoLiteral for i64 {
51 fn into_literal(self) -> LiteralValue {
52 LiteralValue::Int(self)
53 }
54}
55
56impl IntoLiteral for i32 {
57 fn into_literal(self) -> LiteralValue {
58 LiteralValue::Int(self as i64)
59 }
60}
61
62impl IntoLiteral for bool {
63 fn into_literal(self) -> LiteralValue {
64 LiteralValue::Boolean(self)
65 }
66}
67
68impl IntoLiteral for String {
69 fn into_literal(self) -> LiteralValue {
70 LiteralValue::Text(self)
71 }
72}
73
74impl IntoLiteral for &str {
75 fn into_literal(self) -> LiteralValue {
76 LiteralValue::Text(self.to_string())
77 }
78}
79
80pub type StyleId = u32;
81
82#[derive(Clone, Debug, Default)]
83pub struct BackendCaps {
84 pub read: bool,
85 pub write: bool,
86 pub streaming: bool,
87 pub tables: bool,
88 pub named_ranges: bool,
89 pub formulas: bool,
90 pub styles: bool,
91 pub lazy_loading: bool,
92 pub random_access: bool,
93 pub bytes_input: bool,
94
95 pub date_system_1904: bool,
97 pub merged_cells: bool,
98 pub rich_text: bool,
99 pub hyperlinks: bool,
100 pub data_validations: bool,
101 pub shared_formulas: bool,
102}
103
104#[derive(Clone, Debug)]
105pub struct SheetData {
106 pub cells: BTreeMap<(u32, u32), CellData>,
107 pub dimensions: Option<(u32, u32)>,
108 pub tables: Vec<TableDefinition>,
109 pub named_ranges: Vec<NamedRange>,
110 pub date_system_1904: bool,
111 pub merged_cells: Vec<MergedRange>,
112 pub hidden: bool,
113 pub row_hidden_manual: Vec<u32>,
114 pub row_hidden_filter: Vec<u32>,
115}
116
117#[cfg_attr(feature = "json", derive(Serialize, Deserialize))]
118#[cfg_attr(feature = "json", serde(rename_all = "lowercase"))]
119#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
120pub enum NamedRangeScope {
121 #[default]
122 Workbook,
123 Sheet,
124}
125
126#[cfg_attr(feature = "json", derive(Serialize, Deserialize))]
127#[derive(Clone, Debug)]
128pub struct NamedRange {
129 pub name: String,
130 #[cfg_attr(feature = "json", serde(default))]
131 pub scope: NamedRangeScope,
132 pub address: RangeAddress,
133}
134
135#[cfg_attr(feature = "json", derive(Serialize, Deserialize))]
139#[cfg_attr(feature = "json", serde(rename_all = "lowercase"))]
140#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)]
141pub enum DefinedNameScope {
142 #[default]
143 Workbook,
144 Sheet,
145}
146
147#[cfg_attr(feature = "json", derive(Serialize, Deserialize))]
148#[cfg_attr(feature = "json", serde(tag = "type", rename_all = "lowercase"))]
149#[derive(Clone, Debug, PartialEq)]
150pub enum DefinedNameDefinition {
151 Range { address: RangeAddress },
152 Literal { value: LiteralValue },
153}
154
155#[cfg_attr(feature = "json", derive(Serialize, Deserialize))]
156#[derive(Clone, Debug, PartialEq)]
157pub struct DefinedName {
158 pub name: String,
159
160 #[cfg_attr(feature = "json", serde(default))]
161 pub scope: DefinedNameScope,
162
163 #[cfg_attr(
167 feature = "json",
168 serde(default, skip_serializing_if = "Option::is_none")
169 )]
170 pub scope_sheet: Option<String>,
171
172 pub definition: DefinedNameDefinition,
173}
174
175#[cfg_attr(feature = "json", derive(Serialize, Deserialize))]
176#[derive(Clone, Debug)]
177pub struct TableDefinition {
178 pub name: String,
179 pub range: (u32, u32, u32, u32),
180 #[cfg_attr(feature = "json", serde(default = "default_true"))]
187 pub header_row: bool,
188 pub headers: Vec<String>,
189 pub totals_row: bool,
190}
191
192#[cfg(feature = "json")]
193fn default_true() -> bool {
194 true
195}
196
197#[cfg_attr(feature = "json", derive(Serialize, Deserialize))]
198#[derive(Clone, Debug)]
199pub struct MergedRange {
200 pub start_row: u32,
201 pub start_col: u32,
202 pub end_row: u32,
203 pub end_col: u32,
204}
205
206impl MergedRange {
207 pub fn contains(&self, row: u32, col: u32) -> bool {
208 row >= self.start_row && row <= self.end_row && col >= self.start_col && col <= self.end_col
209 }
210}
211
212#[derive(Clone, Copy, Debug)]
213pub enum AccessGranularity {
214 Cell, Range, Sheet, Workbook, }
219
220#[derive(Clone, Debug)]
221pub enum LoadStrategy {
222 EagerAll,
224
225 EagerSheet,
227
228 LazyRange { row_chunk: usize, col_chunk: usize },
230
231 LazyCell,
233
234 WriteOnly,
236}
237
238#[derive(Clone, Debug, Default, PartialEq, Eq)]
239pub struct AdapterLoadStats {
240 pub formula_cells_observed: Option<u64>,
241 pub value_cells_observed: Option<u64>,
242 pub value_slots_handed_to_engine: Option<u64>,
243 pub formula_cells_handed_to_engine: Option<u64>,
244 pub shared_formula_tags_observed: Option<u64>,
245}
246
247#[derive(Clone, Debug, Default, PartialEq)]
260pub struct CalcSettings {
261 pub iterate: bool,
264 pub iterate_count: Option<u32>,
267 pub iterate_delta: Option<f64>,
270 pub calc_mode: Option<String>,
273 pub full_calc_on_load: Option<bool>,
275}
276
277pub trait SpreadsheetReader: Send + Sync {
278 type Error: std::error::Error + Send + Sync + 'static;
279
280 fn access_granularity(&self) -> AccessGranularity;
281 fn capabilities(&self) -> BackendCaps;
282 fn sheet_names(&self) -> Result<Vec<String>, Self::Error>;
283
284 fn load_stats(&self) -> Option<AdapterLoadStats> {
285 None
286 }
287
288 fn defined_names(&mut self) -> Result<Vec<DefinedName>, Self::Error> {
292 Ok(Vec::new())
293 }
294
295 fn calc_settings(&self) -> Option<CalcSettings> {
301 None
302 }
303
304 fn open_path<P: AsRef<Path>>(path: P) -> Result<Self, Self::Error>
306 where
307 Self: Sized;
308
309 fn open_reader(reader: Box<dyn Read + Send + Sync>) -> Result<Self, Self::Error>
310 where
311 Self: Sized;
312
313 fn open_bytes(data: Vec<u8>) -> Result<Self, Self::Error>
314 where
315 Self: Sized;
316
317 fn read_cell(
318 &mut self,
319 sheet: &str,
320 row: u32,
321 col: u32,
322 ) -> Result<Option<CellData>, Self::Error> {
323 let mut range = self.read_range(sheet, (row, col), (row, col))?;
325 Ok(range.remove(&(row, col)))
326 }
327
328 fn read_range(
329 &mut self,
330 sheet: &str,
331 start: (u32, u32),
332 end: (u32, u32),
333 ) -> Result<BTreeMap<(u32, u32), CellData>, Self::Error>;
334
335 fn read_sheet(&mut self, sheet: &str) -> Result<SheetData, Self::Error>;
336
337 fn sheet_bounds(&self, sheet: &str) -> Option<(u32, u32)>;
338 fn is_loaded(&self, sheet: &str, row: Option<u32>, col: Option<u32>) -> bool;
339}
340
341pub trait SpreadsheetWriter: Send + Sync {
342 type Error: std::error::Error + Send + Sync + 'static;
343
344 fn write_cell(
345 &mut self,
346 sheet: &str,
347 row: u32,
348 col: u32,
349 data: CellData,
350 ) -> Result<(), Self::Error>;
351
352 fn write_range(
353 &mut self,
354 sheet: &str,
355 cells: BTreeMap<(u32, u32), CellData>,
356 ) -> Result<(), Self::Error>;
357
358 fn clear_range(
359 &mut self,
360 sheet: &str,
361 start: (u32, u32),
362 end: (u32, u32),
363 ) -> Result<(), Self::Error>;
364
365 fn create_sheet(&mut self, name: &str) -> Result<(), Self::Error>;
366 fn delete_sheet(&mut self, name: &str) -> Result<(), Self::Error>;
367 fn rename_sheet(&mut self, old: &str, new: &str) -> Result<(), Self::Error>;
368
369 fn flush(&mut self) -> Result<(), Self::Error>;
370 fn save(&mut self) -> Result<(), Self::Error> {
371 self.save_to(SaveDestination::InPlace).map(|_| ())
372 }
373
374 fn save_to<'a>(&mut self, dest: SaveDestination<'a>) -> Result<Option<Vec<u8>>, Self::Error> {
377 let _ = dest;
378 unreachable!("save_to must be implemented by writer backends that expose persistence");
379 }
380
381 fn save_as_path<P: AsRef<std::path::Path>>(&mut self, path: P) -> Result<(), Self::Error> {
382 self.save_to(SaveDestination::Path(path.as_ref()))
383 .map(|_| ())
384 }
385
386 fn save_to_bytes(&mut self) -> Result<Vec<u8>, Self::Error> {
387 self.save_to(SaveDestination::Bytes)
388 .map(|opt| opt.unwrap_or_default())
389 }
390
391 fn write_to<W: Write>(&mut self, writer: &mut W) -> Result<(), Self::Error> {
392 self.save_to(SaveDestination::Writer(writer)).map(|_| ())
393 }
394}
395
396pub enum SaveDestination<'a> {
398 InPlace, Path(&'a std::path::Path), Writer(&'a mut dyn Write), Bytes, }
403
404pub trait SpreadsheetIO: SpreadsheetReader + SpreadsheetWriter {}