Skip to main content

formualizer_eval/engine/arena/
data_store.rs

1/// Unified data storage for all value types using arenas
2/// Provides conversion between LiteralValue and ValueRef
3use super::array::ArrayArena;
4use super::ast::{AstArena, AstNodeId, CompactRefType, SheetKey};
5use super::error_arena::{ErrorArena, ErrorRef};
6use super::scalar::ScalarArena;
7use super::string_interner::{StringId, StringInterner};
8use super::value_ref::ValueRef;
9use crate::engine::sheet_registry::SheetRegistry;
10use formualizer_common::{ExcelError, ExcelErrorKind, LiteralValue};
11use formualizer_parse::parser::{
12    ASTNode, ASTNodeType, ExternalBookRef, ExternalReference, ReferenceType, TableReference,
13};
14
15/// Centralized data storage using arenas
16#[derive(Debug)]
17pub struct DataStore {
18    /// Scalar values (floats and large integers)
19    scalars: ScalarArena,
20
21    /// String values
22    strings: StringInterner,
23
24    /// Array values
25    arrays: ArrayArena,
26
27    /// AST nodes for formulas
28    asts: AstArena,
29
30    /// Error storage with message preservation
31    errors: ErrorArena,
32}
33
34impl DataStore {
35    pub fn new() -> Self {
36        Self {
37            scalars: ScalarArena::new(),
38            strings: StringInterner::new(),
39            arrays: ArrayArena::new(),
40            asts: AstArena::new(),
41            errors: ErrorArena::new(),
42        }
43    }
44
45    /// Batch store literal values; returns ValueRefs in same order.
46    pub fn store_values_batch<I>(&mut self, values: I) -> Vec<ValueRef>
47    where
48        I: IntoIterator<Item = LiteralValue>,
49    {
50        let iter = values.into_iter();
51        let (lower, _) = iter.size_hint();
52        let mut out = Vec::with_capacity(lower);
53        for v in iter {
54            out.push(self.store_value(v));
55        }
56        out
57    }
58
59    /// Batch store ASTs; returns AstNodeIds in same order.
60    pub fn store_asts_batch<'a, I>(
61        &mut self,
62        asts: I,
63        sheet_registry: &SheetRegistry,
64    ) -> Vec<AstNodeId>
65    where
66        I: IntoIterator<Item = &'a ASTNode>,
67    {
68        let iter = asts.into_iter();
69        let (lower, _) = iter.size_hint();
70        let mut out = Vec::with_capacity(lower);
71        for ast in iter {
72            out.push(self.store_ast(ast, sheet_registry));
73        }
74        out
75    }
76
77    pub fn with_capacity(estimated_cells: usize) -> Self {
78        Self {
79            scalars: ScalarArena::with_capacity(estimated_cells),
80            strings: StringInterner::with_capacity(estimated_cells / 10),
81            arrays: ArrayArena::with_capacity(estimated_cells / 100),
82            asts: AstArena::with_capacity(estimated_cells / 2),
83            errors: ErrorArena::with_capacity(estimated_cells / 20),
84        }
85    }
86
87    /// Store a LiteralValue and return a ValueRef
88    pub fn store_value(&mut self, value: LiteralValue) -> ValueRef {
89        match value {
90            LiteralValue::Empty => ValueRef::empty(),
91
92            LiteralValue::Number(n) => {
93                // Store as float in scalar arena
94                let idx = self.scalars.insert_float(n);
95                ValueRef::number(idx.as_u32())
96            }
97
98            LiteralValue::Text(s) => {
99                let id = self.strings.intern(&s);
100                ValueRef::string(id.as_u32())
101            }
102
103            LiteralValue::Boolean(b) => ValueRef::boolean(b),
104
105            LiteralValue::Error(err) => self.store_error(&err),
106
107            LiteralValue::Array(array) => {
108                // Convert nested array to ValueRefs
109                let rows = array.len() as u32;
110                let cols = array.first().map(|r| r.len()).unwrap_or(0) as u32;
111
112                let elements: Vec<ValueRef> = array
113                    .into_iter()
114                    .flatten()
115                    .map(|v| self.store_value(v))
116                    .collect();
117
118                let array_ref = self.arrays.insert(rows, cols, elements);
119                ValueRef::array(array_ref.as_u32())
120            }
121
122            LiteralValue::DateTime(dt) => {
123                // Store serial number as float
124                let serial = formualizer_common::datetime_to_serial(&dt);
125                let idx = self.scalars.insert_float(serial);
126                ValueRef::date_time(idx.as_u32())
127            }
128
129            LiteralValue::Date(d) => {
130                // Convert date to datetime at midnight
131                let dt = d.and_hms_opt(0, 0, 0).unwrap();
132                let serial = formualizer_common::datetime_to_serial(&dt);
133                let idx = self.scalars.insert_float(serial);
134                ValueRef::date_time(idx.as_u32())
135            }
136
137            LiteralValue::Time(t) => {
138                // Store time as fractional day
139                use chrono::Timelike;
140                let seconds = (t.hour() * 3600 + t.minute() * 60 + t.second()) as f64;
141                let fraction = seconds / 86400.0;
142                let idx = self.scalars.insert_float(fraction);
143                ValueRef::date_time(idx.as_u32())
144            }
145
146            LiteralValue::Duration(dur) => {
147                // Store as integer seconds (chrono::Duration has num_seconds())
148                let secs = dur.num_seconds();
149                let idx = self.scalars.insert_integer(secs);
150                let raw_index = idx.as_u32() & 0x7FFF_FFFF;
151                ValueRef::duration(raw_index)
152            }
153
154            LiteralValue::Int(i) => {
155                // Try to use small int optimization
156                if let Some(vref) = ValueRef::small_int(i as i32) {
157                    vref
158                } else {
159                    // Store as large integer
160                    let idx = self.scalars.insert_integer(i);
161                    ValueRef::large_int(idx.as_u32())
162                }
163            }
164
165            LiteralValue::Pending => ValueRef::pending(),
166        }
167    }
168
169    /// Retrieve a LiteralValue from a ValueRef
170    pub fn retrieve_value(&self, value_ref: ValueRef) -> LiteralValue {
171        use super::value_ref::ValueType;
172
173        match value_ref.value_type() {
174            ValueType::Empty => LiteralValue::Empty,
175
176            ValueType::SmallInt => {
177                // Small integers are inlined
178                if let Some(i) = value_ref.as_small_int() {
179                    LiteralValue::Int(i as i64)
180                } else {
181                    LiteralValue::Error(ExcelError::new(ExcelErrorKind::Value))
182                }
183            }
184
185            ValueType::LargeInt => {
186                if let Some(idx) = value_ref.arena_index() {
187                    let scalar_ref = super::scalar::ScalarRef::from_raw(idx | (1 << 31));
188                    if let Some(i) = self.scalars.get_integer(scalar_ref) {
189                        LiteralValue::Int(i)
190                    } else {
191                        LiteralValue::Error(ExcelError::new(ExcelErrorKind::Value))
192                    }
193                } else {
194                    LiteralValue::Error(ExcelError::new(ExcelErrorKind::Value))
195                }
196            }
197
198            ValueType::Number => {
199                if let Some(idx) = value_ref.arena_index() {
200                    let scalar_ref = super::scalar::ScalarRef::from_raw(idx);
201                    if let Some(f) = self.scalars.get_float(scalar_ref) {
202                        LiteralValue::Number(f)
203                    } else {
204                        LiteralValue::Error(ExcelError::new(ExcelErrorKind::Value))
205                    }
206                } else {
207                    LiteralValue::Error(ExcelError::new(ExcelErrorKind::Value))
208                }
209            }
210
211            ValueType::String => {
212                if let Some(idx) = value_ref.arena_index() {
213                    let string_id = StringId::from_raw(idx);
214                    let s = self.strings.resolve(string_id);
215                    LiteralValue::Text(s.to_string())
216                } else {
217                    LiteralValue::Error(ExcelError::new(ExcelErrorKind::Value))
218                }
219            }
220
221            ValueType::Boolean => {
222                if let Some(b) = value_ref.as_boolean() {
223                    LiteralValue::Boolean(b)
224                } else {
225                    LiteralValue::Error(ExcelError::new(ExcelErrorKind::Value))
226                }
227            }
228
229            ValueType::Error => {
230                if let Some(error_ref_raw) = value_ref.as_error_ref() {
231                    let error_ref = ErrorRef::from_raw(error_ref_raw);
232                    if let Some(error) = self.errors.get(error_ref) {
233                        LiteralValue::Error(error)
234                    } else {
235                        LiteralValue::Error(ExcelError::new(ExcelErrorKind::Value))
236                    }
237                } else {
238                    LiteralValue::Error(ExcelError::new(ExcelErrorKind::Value))
239                }
240            }
241
242            ValueType::Array => {
243                if let Some(idx) = value_ref.arena_index() {
244                    let array_ref = super::array::ArrayRef::from_raw(idx);
245                    if let Some(array_2d) = self.arrays.get_2d(array_ref) {
246                        // Convert back to LiteralValue array
247                        let result: Vec<Vec<LiteralValue>> = array_2d
248                            .into_iter()
249                            .map(|row| row.into_iter().map(|v| self.retrieve_value(v)).collect())
250                            .collect();
251                        LiteralValue::Array(result)
252                    } else {
253                        LiteralValue::Error(ExcelError::new(ExcelErrorKind::Value))
254                    }
255                } else {
256                    LiteralValue::Error(ExcelError::new(ExcelErrorKind::Value))
257                }
258            }
259
260            ValueType::DateTime => {
261                if let Some(idx) = value_ref.arena_index() {
262                    let scalar_ref = super::scalar::ScalarRef::from_raw(idx);
263                    if let Some(serial) = self.scalars.get_float(scalar_ref) {
264                        let dt = formualizer_common::serial_to_datetime(serial);
265                        LiteralValue::DateTime(dt)
266                    } else {
267                        LiteralValue::Error(ExcelError::new(ExcelErrorKind::Value))
268                    }
269                } else {
270                    LiteralValue::Error(ExcelError::new(ExcelErrorKind::Value))
271                }
272            }
273
274            ValueType::Duration => {
275                if let Some(idx) = value_ref.arena_index() {
276                    let scalar_ref = super::scalar::ScalarRef::from_raw(idx | (1 << 31));
277                    if let Some(secs) = self.scalars.get_integer(scalar_ref) {
278                        let dur = chrono::Duration::seconds(secs);
279                        LiteralValue::Duration(dur)
280                    } else {
281                        LiteralValue::Error(ExcelError::new(ExcelErrorKind::Value))
282                    }
283                } else {
284                    LiteralValue::Error(ExcelError::new(ExcelErrorKind::Value))
285                }
286            }
287
288            ValueType::Pending => LiteralValue::Pending,
289
290            ValueType::FormulaAst => {
291                // Formula ASTs shouldn't be returned as values
292                LiteralValue::Error(ExcelError::new(ExcelErrorKind::Value))
293            }
294        }
295    }
296
297    /// Store an AST node and return its ID
298    pub fn store_ast(&mut self, ast: &ASTNode, sheet_registry: &SheetRegistry) -> AstNodeId {
299        self.convert_ast_node(ast, sheet_registry)
300    }
301
302    /// Retrieve an AST node from its ID
303    pub fn retrieve_ast(&self, id: AstNodeId, sheet_registry: &SheetRegistry) -> Option<ASTNode> {
304        self.reconstruct_ast_node(id, sheet_registry)
305    }
306
307    pub fn resolve_ast_string(&self, id: StringId) -> &str {
308        self.asts.resolve_string(id)
309    }
310
311    pub fn reconstruct_reference_type_for_eval(
312        &self,
313        ref_type: &CompactRefType,
314        sheet_registry: &SheetRegistry,
315    ) -> ReferenceType {
316        self.reconstruct_reference_type(ref_type, sheet_registry)
317    }
318
319    pub fn get_node(&self, id: AstNodeId) -> Option<&super::ast::AstNodeData> {
320        self.asts.get(id)
321    }
322
323    pub fn get_args(&self, id: AstNodeId) -> Option<&[AstNodeId]> {
324        self.asts.get_function_args(id)
325    }
326
327    pub fn get_array_elems(&self, id: AstNodeId) -> Option<(u16, u16, &[AstNodeId])> {
328        self.asts.get_array_elements_info(id)
329    }
330
331    /// Convert ASTNode to arena representation
332    fn convert_ast_node(&mut self, node: &ASTNode, sheet_registry: &SheetRegistry) -> AstNodeId {
333        match &node.node_type {
334            ASTNodeType::Literal(lit) => {
335                let value_ref = self.store_value(lit.clone());
336                self.asts.insert_literal(value_ref)
337            }
338
339            ASTNodeType::Reference {
340                original,
341                reference,
342            } => {
343                let ref_type = self.convert_reference_type(reference, sheet_registry);
344                self.asts.insert_reference(original, ref_type)
345            }
346
347            ASTNodeType::UnaryOp { op, expr } => {
348                let expr_id = self.convert_ast_node(expr, sheet_registry);
349                self.asts.insert_unary_op(op, expr_id)
350            }
351
352            ASTNodeType::BinaryOp { op, left, right } => {
353                let left_id = self.convert_ast_node(left, sheet_registry);
354                let right_id = self.convert_ast_node(right, sheet_registry);
355                self.asts.insert_binary_op(op, left_id, right_id)
356            }
357
358            ASTNodeType::Function { name, args } => {
359                let arg_ids: Vec<AstNodeId> = args
360                    .iter()
361                    .map(|arg| self.convert_ast_node(arg, sheet_registry))
362                    .collect();
363                self.asts.insert_function(name, arg_ids)
364            }
365
366            ASTNodeType::Array(rows) => {
367                let total_elements = rows.iter().map(|r| r.len()).sum();
368                let mut elements = Vec::with_capacity(total_elements);
369
370                let rows_count = rows.len() as u16;
371                let cols_count = rows.first().map(|r| r.len()).unwrap_or(0) as u16;
372
373                for row in rows {
374                    for elem in row {
375                        elements.push(self.convert_ast_node(elem, sheet_registry));
376                    }
377                }
378
379                self.asts.insert_array(rows_count, cols_count, elements)
380            }
381
382            // Postfix call (e.g. LAMBDA immediate-invocation). The arena does
383            // not yet have a dedicated node kind for this, and full evaluator
384            // semantics are out of scope for the parser-side change. Store an
385            // unsupported-formula error literal so that downstream evaluation
386            // surfaces a clear #N/A!-style error instead of silently producing
387            // a wrong result.
388            ASTNodeType::Call { .. } => {
389                let value_ref = self.store_value(LiteralValue::Error(
390                    ExcelError::new(ExcelErrorKind::NImpl)
391                        .with_message("Immediate-invocation calls are not yet supported"),
392                ));
393                self.asts.insert_literal(value_ref)
394            }
395        }
396    }
397
398    /// Convert ReferenceType to CompactRefType
399    fn convert_reference_type(
400        &mut self,
401        ref_type: &ReferenceType,
402        sheet_registry: &SheetRegistry,
403    ) -> CompactRefType {
404        match ref_type {
405            ReferenceType::Cell {
406                sheet,
407                row,
408                col,
409                row_abs,
410                col_abs,
411            } => {
412                let sheet = match sheet.as_ref() {
413                    Some(s) => match sheet_registry.get_id(s) {
414                        Some(id) => Some(SheetKey::Id(id)),
415                        None => Some(SheetKey::Name(self.asts.strings_mut().intern(s))),
416                    },
417                    None => None,
418                };
419                CompactRefType::Cell {
420                    sheet,
421                    row: *row,
422                    col: *col,
423                    row_abs: *row_abs,
424                    col_abs: *col_abs,
425                }
426            }
427
428            ReferenceType::Range {
429                sheet,
430                start_row,
431                start_col,
432                end_row,
433                end_col,
434                start_row_abs,
435                start_col_abs,
436                end_row_abs,
437                end_col_abs,
438            } => {
439                let sheet = match sheet.as_ref() {
440                    Some(s) => match sheet_registry.get_id(s) {
441                        Some(id) => Some(SheetKey::Id(id)),
442                        None => Some(SheetKey::Name(self.asts.strings_mut().intern(s))),
443                    },
444                    None => None,
445                };
446                // For optional range bounds, use 0/u32::MAX as sentinels for unbounded
447                CompactRefType::Range {
448                    sheet,
449                    start_row: start_row.unwrap_or(0),
450                    start_col: start_col.unwrap_or(0),
451                    end_row: end_row.unwrap_or(u32::MAX),
452                    end_col: end_col.unwrap_or(u32::MAX),
453                    start_row_abs: *start_row_abs,
454                    start_col_abs: *start_col_abs,
455                    end_row_abs: *end_row_abs,
456                    end_col_abs: *end_col_abs,
457                }
458            }
459
460            ReferenceType::External(ext) => {
461                let raw_id = self.asts.strings_mut().intern(&ext.raw);
462                let book_id = self.asts.strings_mut().intern(ext.book.token());
463                let sheet_id = self.asts.strings_mut().intern(&ext.sheet);
464                CompactRefType::External {
465                    raw_id,
466                    book_id,
467                    sheet_id,
468                    kind: ext.kind,
469                }
470            }
471
472            ReferenceType::NamedRange(name) => {
473                let string_id = self.asts.strings_mut().intern(name);
474                CompactRefType::NamedRange(string_id)
475            }
476
477            ReferenceType::Table(table_ref) => {
478                let name_id = self.asts.strings_mut().intern(&table_ref.name);
479                let specifier_id = table_ref
480                    .specifier
481                    .as_ref()
482                    .map(|specifier| self.asts.intern_table_specifier(specifier));
483                CompactRefType::Table {
484                    name_id,
485                    specifier_id,
486                }
487            }
488
489            ReferenceType::Cell3D {
490                sheet_first,
491                sheet_last,
492                row,
493                col,
494                row_abs,
495                col_abs,
496            } => {
497                let sheet_first = self.asts.strings_mut().intern(sheet_first);
498                let sheet_last = self.asts.strings_mut().intern(sheet_last);
499                CompactRefType::Cell3D {
500                    sheet_first,
501                    sheet_last,
502                    row: *row,
503                    col: *col,
504                    row_abs: *row_abs,
505                    col_abs: *col_abs,
506                }
507            }
508
509            ReferenceType::Range3D {
510                sheet_first,
511                sheet_last,
512                start_row,
513                start_col,
514                end_row,
515                end_col,
516                start_row_abs,
517                start_col_abs,
518                end_row_abs,
519                end_col_abs,
520            } => {
521                let sheet_first = self.asts.strings_mut().intern(sheet_first);
522                let sheet_last = self.asts.strings_mut().intern(sheet_last);
523                CompactRefType::Range3D {
524                    sheet_first,
525                    sheet_last,
526                    start_row: start_row.unwrap_or(0),
527                    start_col: start_col.unwrap_or(0),
528                    end_row: end_row.unwrap_or(u32::MAX),
529                    end_col: end_col.unwrap_or(u32::MAX),
530                    start_row_abs: *start_row_abs,
531                    start_col_abs: *start_col_abs,
532                    end_row_abs: *end_row_abs,
533                    end_col_abs: *end_col_abs,
534                }
535            }
536        }
537    }
538
539    /// Reconstruct an ASTNode from arena representation
540    fn reconstruct_ast_node(
541        &self,
542        id: AstNodeId,
543        sheet_registry: &SheetRegistry,
544    ) -> Option<ASTNode> {
545        use super::ast::AstNodeData;
546
547        let node_data = self.asts.get(id)?;
548
549        let node_type = match node_data {
550            AstNodeData::Literal(value_ref) => {
551                let lit = self.retrieve_value(*value_ref);
552                ASTNodeType::Literal(lit)
553            }
554
555            AstNodeData::Reference {
556                original_id,
557                ref_type,
558            } => {
559                let original = self.asts.resolve_string(*original_id).to_string();
560                let reference = self.reconstruct_reference_type(ref_type, sheet_registry);
561                ASTNodeType::Reference {
562                    original,
563                    reference,
564                }
565            }
566
567            AstNodeData::UnaryOp { op_id, expr_id } => {
568                let op = self.asts.resolve_string(*op_id).to_string();
569                let expr = Box::new(self.reconstruct_ast_node(*expr_id, sheet_registry)?);
570                ASTNodeType::UnaryOp { op, expr }
571            }
572
573            AstNodeData::BinaryOp {
574                op_id,
575                left_id,
576                right_id,
577            } => {
578                let op = self.asts.resolve_string(*op_id).to_string();
579                let left = Box::new(self.reconstruct_ast_node(*left_id, sheet_registry)?);
580                let right = Box::new(self.reconstruct_ast_node(*right_id, sheet_registry)?);
581                ASTNodeType::BinaryOp { op, left, right }
582            }
583
584            AstNodeData::Function { name_id, .. } => {
585                let name = self.asts.resolve_string(*name_id).to_string();
586                let arg_ids = self.asts.get_function_args(id)?;
587                let args: Vec<ASTNode> = arg_ids
588                    .iter()
589                    .filter_map(|&arg_id| self.reconstruct_ast_node(arg_id, sheet_registry))
590                    .collect();
591                ASTNodeType::Function { name, args }
592            }
593
594            AstNodeData::Array { rows, cols, .. } => {
595                let elements = self.asts.get_array_elements(id)?;
596                let mut result = Vec::with_capacity(*rows as usize);
597
598                for r in 0..*rows {
599                    let mut row = Vec::with_capacity(*cols as usize);
600                    for c in 0..*cols {
601                        let idx = (r * *cols + c) as usize;
602                        if let Some(&elem_id) = elements.get(idx)
603                            && let Some(node) = self.reconstruct_ast_node(elem_id, sheet_registry)
604                        {
605                            row.push(node);
606                        }
607                    }
608                    result.push(row);
609                }
610
611                ASTNodeType::Array(result)
612            }
613        };
614
615        Some(ASTNode {
616            node_type,
617            source_token: None, // Token information is not preserved in arena
618            contains_volatile: false,
619        })
620    }
621
622    /// Reconstruct a ReferenceType from CompactRefType
623    fn reconstruct_reference_type(
624        &self,
625        ref_type: &CompactRefType,
626        sheet_registry: &SheetRegistry,
627    ) -> ReferenceType {
628        match ref_type {
629            CompactRefType::Cell {
630                sheet,
631                row,
632                col,
633                row_abs,
634                col_abs,
635            } => {
636                let sheet = match sheet {
637                    Some(SheetKey::Id(id)) => Some(sheet_registry.name(*id).to_string()),
638                    Some(SheetKey::Name(name_id)) => {
639                        Some(self.asts.resolve_string(*name_id).to_string())
640                    }
641                    None => None,
642                };
643                ReferenceType::Cell {
644                    sheet,
645                    row: *row,
646                    col: *col,
647                    row_abs: *row_abs,
648                    col_abs: *col_abs,
649                }
650            }
651
652            CompactRefType::Range {
653                sheet,
654                start_row,
655                start_col,
656                end_row,
657                end_col,
658                start_row_abs,
659                start_col_abs,
660                end_row_abs,
661                end_col_abs,
662            } => {
663                let sheet = match sheet {
664                    Some(SheetKey::Id(id)) => Some(sheet_registry.name(*id).to_string()),
665                    Some(SheetKey::Name(name_id)) => {
666                        Some(self.asts.resolve_string(*name_id).to_string())
667                    }
668                    None => None,
669                };
670                // Convert sentinel values back to None
671                ReferenceType::Range {
672                    sheet,
673                    start_row: if *start_row == 0 {
674                        None
675                    } else {
676                        Some(*start_row)
677                    },
678                    start_col: if *start_col == 0 {
679                        None
680                    } else {
681                        Some(*start_col)
682                    },
683                    end_row: if *end_row == u32::MAX {
684                        None
685                    } else {
686                        Some(*end_row)
687                    },
688                    end_col: if *end_col == u32::MAX {
689                        None
690                    } else {
691                        Some(*end_col)
692                    },
693                    start_row_abs: *start_row_abs,
694                    start_col_abs: *start_col_abs,
695                    end_row_abs: *end_row_abs,
696                    end_col_abs: *end_col_abs,
697                }
698            }
699
700            CompactRefType::External {
701                raw_id,
702                book_id,
703                sheet_id,
704                kind,
705            } => {
706                let raw = self.asts.resolve_string(*raw_id).to_string();
707                let book = self.asts.resolve_string(*book_id).to_string();
708                let sheet = self.asts.resolve_string(*sheet_id).to_string();
709                ReferenceType::External(ExternalReference {
710                    raw,
711                    book: ExternalBookRef::Token(book),
712                    sheet,
713                    kind: *kind,
714                })
715            }
716
717            CompactRefType::NamedRange(string_id) => {
718                let name = self.asts.resolve_string(*string_id).to_string();
719                ReferenceType::NamedRange(name)
720            }
721
722            CompactRefType::Table {
723                name_id,
724                specifier_id,
725            } => {
726                let name = self.asts.resolve_string(*name_id).to_string();
727                let specifier = specifier_id
728                    .and_then(|id| self.asts.resolve_table_specifier(id))
729                    .cloned();
730                ReferenceType::Table(TableReference { name, specifier })
731            }
732
733            CompactRefType::Cell3D {
734                sheet_first,
735                sheet_last,
736                row,
737                col,
738                row_abs,
739                col_abs,
740            } => ReferenceType::Cell3D {
741                sheet_first: self.asts.resolve_string(*sheet_first).to_string(),
742                sheet_last: self.asts.resolve_string(*sheet_last).to_string(),
743                row: *row,
744                col: *col,
745                row_abs: *row_abs,
746                col_abs: *col_abs,
747            },
748
749            CompactRefType::Range3D {
750                sheet_first,
751                sheet_last,
752                start_row,
753                start_col,
754                end_row,
755                end_col,
756                start_row_abs,
757                start_col_abs,
758                end_row_abs,
759                end_col_abs,
760            } => ReferenceType::Range3D {
761                sheet_first: self.asts.resolve_string(*sheet_first).to_string(),
762                sheet_last: self.asts.resolve_string(*sheet_last).to_string(),
763                start_row: if *start_row == 0 {
764                    None
765                } else {
766                    Some(*start_row)
767                },
768                start_col: if *start_col == 0 {
769                    None
770                } else {
771                    Some(*start_col)
772                },
773                end_row: if *end_row == u32::MAX {
774                    None
775                } else {
776                    Some(*end_row)
777                },
778                end_col: if *end_col == u32::MAX {
779                    None
780                } else {
781                    Some(*end_col)
782                },
783                start_row_abs: *start_row_abs,
784                start_col_abs: *start_col_abs,
785                end_row_abs: *end_row_abs,
786                end_col_abs: *end_col_abs,
787            },
788        }
789    }
790
791    /// Store an error with message preservation
792    fn store_error(&mut self, error: &ExcelError) -> ValueRef {
793        let error_ref = self.errors.insert(error);
794        ValueRef::error(error_ref.as_u32())
795    }
796
797    /// Get memory usage statistics
798    pub fn memory_usage(&self) -> DataStoreStats {
799        DataStoreStats {
800            scalar_bytes: self.scalars.memory_usage(),
801            string_bytes: self.strings.memory_usage(),
802            array_bytes: self.arrays.memory_usage(),
803            ast_bytes: self.asts.memory_usage(),
804            error_bytes: self.errors.memory_usage(),
805            total_scalars: self.scalars.len(),
806            total_strings: self.strings.len(),
807            total_arrays: self.arrays.len(),
808            total_ast_nodes: self.asts.stats().node_count,
809            total_errors: self.errors.len(),
810        }
811    }
812
813    /// Clear all data from the store
814    pub fn clear(&mut self) {
815        self.scalars.clear();
816        self.strings.clear();
817        self.arrays.clear();
818        self.asts.clear();
819        self.errors.clear();
820    }
821}
822
823impl Default for DataStore {
824    fn default() -> Self {
825        Self::new()
826    }
827}
828
829/// Statistics about data store memory usage
830#[derive(Debug, Clone)]
831pub struct DataStoreStats {
832    pub scalar_bytes: usize,
833    pub string_bytes: usize,
834    pub array_bytes: usize,
835    pub ast_bytes: usize,
836    pub error_bytes: usize,
837    pub total_scalars: usize,
838    pub total_strings: usize,
839    pub total_arrays: usize,
840    pub total_ast_nodes: usize,
841    pub total_errors: usize,
842}
843
844impl DataStoreStats {
845    pub fn total_bytes(&self) -> usize {
846        self.scalar_bytes + self.string_bytes + self.array_bytes + self.ast_bytes + self.error_bytes
847    }
848}
849
850// Helper trait implementations for ArrayRef and ScalarRef
851impl super::array::ArrayRef {
852    pub fn from_raw(raw: u32) -> Self {
853        super::array::ArrayRef(raw)
854    }
855}
856
857impl super::scalar::ScalarRef {
858    pub fn from_raw(raw: u32) -> Self {
859        Self { raw }
860    }
861
862    pub fn as_u32(self) -> u32 {
863        self.raw
864    }
865}
866
867#[cfg(test)]
868mod tests {
869    use super::*;
870
871    #[test]
872    fn test_data_store_empty_value() {
873        let mut store = DataStore::new();
874        let value_ref = store.store_value(LiteralValue::Empty);
875        assert!(value_ref.is_empty());
876
877        let retrieved = store.retrieve_value(value_ref);
878        assert_eq!(retrieved, LiteralValue::Empty);
879    }
880
881    #[test]
882    fn test_data_store_number() {
883        let mut store = DataStore::new();
884        let value_ref = store.store_value(LiteralValue::Number(42.5));
885
886        let retrieved = store.retrieve_value(value_ref);
887        assert_eq!(retrieved, LiteralValue::Number(42.5));
888    }
889
890    #[test]
891    fn test_data_store_text() {
892        let mut store = DataStore::new();
893        let value_ref = store.store_value(LiteralValue::Text("Hello".to_string()));
894
895        let retrieved = store.retrieve_value(value_ref);
896        assert_eq!(retrieved, LiteralValue::Text("Hello".to_string()));
897    }
898
899    #[test]
900    fn test_data_store_boolean() {
901        let mut store = DataStore::new();
902
903        let true_ref = store.store_value(LiteralValue::Boolean(true));
904        let false_ref = store.store_value(LiteralValue::Boolean(false));
905
906        assert_eq!(store.retrieve_value(true_ref), LiteralValue::Boolean(true));
907        assert_eq!(
908            store.retrieve_value(false_ref),
909            LiteralValue::Boolean(false)
910        );
911    }
912
913    #[test]
914    fn test_data_store_error() {
915        let mut store = DataStore::new();
916
917        let error = ExcelError::new(ExcelErrorKind::Div);
918        let value_ref = store.store_value(LiteralValue::Error(error.clone()));
919
920        let retrieved = store.retrieve_value(value_ref);
921        match retrieved {
922            LiteralValue::Error(e) => assert_eq!(e.kind, ExcelErrorKind::Div),
923            _ => panic!("Expected error"),
924        }
925    }
926
927    #[test]
928    fn test_data_store_array() {
929        let mut store = DataStore::new();
930
931        let array = vec![
932            vec![LiteralValue::Number(1.0), LiteralValue::Number(2.0)],
933            vec![LiteralValue::Number(3.0), LiteralValue::Number(4.0)],
934        ];
935
936        let value_ref = store.store_value(LiteralValue::Array(array.clone()));
937        let retrieved = store.retrieve_value(value_ref);
938
939        assert_eq!(retrieved, LiteralValue::Array(array));
940    }
941
942    #[test]
943    fn test_data_store_ast_literal() {
944        let mut store = DataStore::new();
945        let mut sheet_registry = SheetRegistry::new();
946        sheet_registry.id_for("Sheet1");
947
948        let ast = ASTNode {
949            node_type: ASTNodeType::Literal(LiteralValue::Number(42.0)),
950            source_token: None,
951            contains_volatile: false,
952        };
953
954        let ast_id = store.store_ast(&ast, &sheet_registry);
955        let retrieved = store.retrieve_ast(ast_id, &sheet_registry).unwrap();
956
957        match retrieved.node_type {
958            ASTNodeType::Literal(lit) => assert_eq!(lit, LiteralValue::Number(42.0)),
959            _ => panic!("Expected literal"),
960        }
961    }
962
963    #[test]
964    fn test_data_store_ast_binary_op() {
965        let mut store = DataStore::new();
966        let mut sheet_registry = SheetRegistry::new();
967        sheet_registry.id_for("Sheet1");
968
969        let ast = ASTNode {
970            node_type: ASTNodeType::BinaryOp {
971                op: "+".to_string(),
972                left: Box::new(ASTNode {
973                    node_type: ASTNodeType::Literal(LiteralValue::Number(1.0)),
974                    source_token: None,
975                    contains_volatile: false,
976                }),
977                right: Box::new(ASTNode {
978                    node_type: ASTNodeType::Literal(LiteralValue::Number(2.0)),
979                    source_token: None,
980                    contains_volatile: false,
981                }),
982            },
983            source_token: None,
984            contains_volatile: false,
985        };
986
987        let ast_id = store.store_ast(&ast, &sheet_registry);
988        let retrieved = store.retrieve_ast(ast_id, &sheet_registry).unwrap();
989
990        match retrieved.node_type {
991            ASTNodeType::BinaryOp { op, left, right } => {
992                assert_eq!(op, "+");
993                match left.node_type {
994                    ASTNodeType::Literal(lit) => assert_eq!(lit, LiteralValue::Number(1.0)),
995                    _ => panic!("Expected literal"),
996                }
997                match right.node_type {
998                    ASTNodeType::Literal(lit) => assert_eq!(lit, LiteralValue::Number(2.0)),
999                    _ => panic!("Expected literal"),
1000                }
1001            }
1002            _ => panic!("Expected binary op"),
1003        }
1004    }
1005
1006    #[test]
1007    fn test_data_store_ast_function() {
1008        let mut store = DataStore::new();
1009        let mut sheet_registry = SheetRegistry::new();
1010        sheet_registry.id_for("Sheet1");
1011
1012        let ast = ASTNode {
1013            node_type: ASTNodeType::Function {
1014                name: "SUM".to_string(),
1015                args: vec![
1016                    ASTNode {
1017                        node_type: ASTNodeType::Literal(LiteralValue::Number(1.0)),
1018                        source_token: None,
1019                        contains_volatile: false,
1020                    },
1021                    ASTNode {
1022                        node_type: ASTNodeType::Literal(LiteralValue::Number(2.0)),
1023                        source_token: None,
1024                        contains_volatile: false,
1025                    },
1026                ],
1027            },
1028            source_token: None,
1029            contains_volatile: false,
1030        };
1031
1032        let ast_id = store.store_ast(&ast, &sheet_registry);
1033        let retrieved = store.retrieve_ast(ast_id, &sheet_registry).unwrap();
1034
1035        match retrieved.node_type {
1036            ASTNodeType::Function { name, args } => {
1037                assert_eq!(name, "SUM");
1038                assert_eq!(args.len(), 2);
1039            }
1040            _ => panic!("Expected function"),
1041        }
1042    }
1043
1044    #[test]
1045    fn test_data_store_memory_stats() {
1046        let mut store = DataStore::new();
1047
1048        // Add some data
1049        store.store_value(LiteralValue::Number(42.0));
1050        store.store_value(LiteralValue::Text("Hello".to_string()));
1051        store.store_value(LiteralValue::Array(vec![vec![LiteralValue::Number(1.0)]]));
1052
1053        let stats = store.memory_usage();
1054        assert!(stats.total_bytes() > 0);
1055        assert_eq!(stats.total_scalars, 2); // 42.0 and 1.0
1056        assert_eq!(stats.total_strings, 1); // "Hello"
1057        assert_eq!(stats.total_arrays, 1);
1058    }
1059
1060    #[test]
1061    fn test_data_store_clear() {
1062        let mut store = DataStore::new();
1063
1064        store.store_value(LiteralValue::Number(42.0));
1065        store.store_value(LiteralValue::Text("Hello".to_string()));
1066
1067        let stats = store.memory_usage();
1068        assert!(stats.total_scalars > 0);
1069        assert!(stats.total_strings > 0);
1070
1071        store.clear();
1072
1073        let stats = store.memory_usage();
1074        assert_eq!(stats.total_scalars, 0);
1075        assert_eq!(stats.total_strings, 0);
1076    }
1077}