1use crate::engine::lookup_index_cache::{LookupAxis, LookupIndex};
2use crate::engine::range_view::RangeView;
3use crate::engine::row_visibility::VisibilityMaskMode;
4pub use crate::function::Function;
5use crate::interpreter::Interpreter;
6use crate::reference::CellRef;
7use formualizer_common::{
8 LiteralValue,
9 error::{ExcelError, ExcelErrorKind},
10};
11use std::any::Any;
12use std::borrow::Cow;
13use std::fmt::Debug;
14use std::sync::Arc;
15
16use formualizer_parse::parser::{ASTNode, ASTNodeType, ReferenceType, TableSpecifier};
17
18#[derive(Clone, Debug, Eq, PartialEq)]
19pub struct ReferenceInfo {
20 pub first_sheet_index: Option<usize>,
22 pub sheet_count: Option<usize>,
24 pub first_cell: Option<CellRef>,
26}
27
28pub trait Range: Debug + Send + Sync {
31 fn get(&self, row: usize, col: usize) -> Result<LiteralValue, ExcelError>;
32 fn dimensions(&self) -> (usize, usize);
33
34 fn is_sparse(&self) -> bool {
35 false
36 }
37
38 fn is_infinite(&self) -> bool {
40 false
41 }
42
43 fn materialise(&self) -> Cow<'_, [Vec<LiteralValue>]> {
44 Cow::Owned(
45 (0..self.dimensions().0)
46 .map(|r| {
47 (0..self.dimensions().1)
48 .map(|c| self.get(r, c).unwrap_or(LiteralValue::Empty))
49 .collect()
50 })
51 .collect(),
52 )
53 }
54
55 fn iter_cells<'a>(&'a self) -> Box<dyn Iterator<Item = LiteralValue> + 'a> {
56 let (rows, cols) = self.dimensions();
57 Box::new((0..rows).flat_map(move |r| (0..cols).map(move |c| self.get(r, c).unwrap())))
58 }
59 fn iter_rows<'a>(&'a self) -> Box<dyn Iterator<Item = Vec<LiteralValue>> + 'a> {
60 let (rows, cols) = self.dimensions();
61 Box::new((0..rows).map(move |r| (0..cols).map(|c| self.get(r, c).unwrap()).collect()))
62 }
63
64 fn as_any(&self) -> &dyn Any;
66}
67
68impl Range for Box<dyn Range> {
70 fn get(&self, r: usize, c: usize) -> Result<LiteralValue, ExcelError> {
71 (**self).get(r, c)
72 }
73 fn dimensions(&self) -> (usize, usize) {
74 (**self).dimensions()
75 }
76 fn is_sparse(&self) -> bool {
77 (**self).is_sparse()
78 }
79 fn materialise(&self) -> Cow<'_, [Vec<LiteralValue>]> {
80 (**self).materialise()
81 }
82 fn iter_cells<'a>(&'a self) -> Box<dyn Iterator<Item = LiteralValue> + 'a> {
83 (**self).iter_cells()
84 }
85 fn iter_rows<'a>(&'a self) -> Box<dyn Iterator<Item = Vec<LiteralValue>> + 'a> {
86 (**self).iter_rows()
87 }
88 fn as_any(&self) -> &dyn Any {
89 (**self).as_any()
90 }
91}
92
93pub type CowValue<'a> = Cow<'a, LiteralValue>;
96
97pub trait CustomCallable: Send + Sync {
98 fn arity(&self) -> usize;
99
100 fn invoke<'ctx>(
101 &self,
102 interp: &Interpreter<'ctx>,
103 args: &[LiteralValue],
104 ) -> Result<CalcValue<'ctx>, ExcelError>;
105}
106
107#[derive(Clone)]
108pub enum CalcValue<'a> {
109 Scalar(LiteralValue),
110 Range(RangeView<'a>),
111 Callable(Arc<dyn CustomCallable>),
112}
113
114impl<'a> std::fmt::Debug for CalcValue<'a> {
115 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116 match self {
117 CalcValue::Scalar(v) => f.debug_tuple("Scalar").field(v).finish(),
118 CalcValue::Range(rv) => {
119 let (r, c) = rv.dims();
120 f.debug_tuple("Range").field(&(r, c)).finish()
121 }
122 CalcValue::Callable(_) => f.write_str("Callable(<opaque>)"),
123 }
124 }
125}
126
127impl<'a> CalcValue<'a> {
128 pub fn into_literal(self) -> LiteralValue {
129 match self {
130 CalcValue::Scalar(s) => s,
131 CalcValue::Range(rv) => {
132 let (rows, cols) = rv.dims();
133 if rows == 1 && cols == 1 {
134 rv.get_cell(0, 0)
135 } else {
136 let mut data = Vec::with_capacity(rows);
137 let _ = rv.for_each_row(&mut |row| {
140 data.push(row.to_vec());
141 Ok(())
142 });
143 LiteralValue::Array(data)
144 }
145 }
146 CalcValue::Callable(_) => LiteralValue::Error(
147 ExcelError::new(ExcelErrorKind::Calc).with_message("LAMBDA value must be invoked"),
148 ),
149 }
150 }
151
152 pub fn as_scalar(&self) -> Option<&LiteralValue> {
153 match self {
154 CalcValue::Scalar(s) => Some(s),
155 _ => None,
156 }
157 }
158
159 pub fn as_range(&self) -> Option<&RangeView<'a>> {
160 match self {
161 CalcValue::Range(r) => Some(r),
162 _ => None,
163 }
164 }
165
166 pub fn as_callable(&self) -> Option<&Arc<dyn CustomCallable>> {
167 match self {
168 CalcValue::Callable(c) => Some(c),
169 _ => None,
170 }
171 }
172
173 pub fn into_owned(self) -> LiteralValue {
174 self.into_literal()
175 }
176}
177
178impl From<CalcValue<'_>> for LiteralValue {
179 fn from(val: CalcValue<'_>) -> Self {
180 val.into_literal()
181 }
182}
183
184impl<'a> PartialEq<LiteralValue> for CalcValue<'a> {
185 fn eq(&self, other: &LiteralValue) -> bool {
186 match self {
187 CalcValue::Scalar(s) => s == other,
188 CalcValue::Range(rv) => match other {
189 LiteralValue::Array(arr) => {
190 let (rows, cols) = rv.dims();
191 if arr.len() != rows {
192 return false;
193 }
194 for (r, row) in arr.iter().enumerate() {
195 if row.len() != cols {
196 return false;
197 }
198 for (c, cell) in row.iter().enumerate() {
199 if &rv.get_cell(r, c) != cell {
200 return false;
201 }
202 }
203 }
204 true
205 }
206 _ => {
207 let (rows, cols) = rv.dims();
208 rows == 1 && cols == 1 && &rv.get_cell(0, 0) == other
209 }
210 },
211 CalcValue::Callable(_) => false,
212 }
213 }
214}
215
216impl<'a> PartialEq<CalcValue<'a>> for LiteralValue {
217 fn eq(&self, other: &CalcValue<'a>) -> bool {
218 other == self
219 }
220}
221
222pub enum EvaluatedArg<'a> {
223 LiteralValue(CowValue<'a>),
224 Range(Box<dyn Range>),
225}
226
227enum ArgumentExpr<'a> {
228 Ast(&'a ASTNode),
229 Arena {
230 id: crate::engine::arena::AstNodeId,
231 data_store: &'a crate::engine::arena::DataStore,
232 sheet_registry: &'a crate::engine::sheet_registry::SheetRegistry,
233 },
234}
235
236pub struct ArgumentHandle<'a, 'b> {
237 expr: ArgumentExpr<'a>,
238 interp: &'a Interpreter<'b>,
239 cached_ast: std::cell::OnceCell<ASTNode>,
240 cached_ref: std::cell::OnceCell<ReferenceType>,
241}
242
243impl<'a, 'b> ArgumentHandle<'a, 'b> {
244 pub(crate) fn new(node: &'a ASTNode, interp: &'a Interpreter<'b>) -> Self {
245 Self {
246 expr: ArgumentExpr::Ast(node),
247 interp,
248 cached_ast: std::cell::OnceCell::new(),
249 cached_ref: std::cell::OnceCell::new(),
250 }
251 }
252
253 pub(crate) fn new_arena(
254 id: crate::engine::arena::AstNodeId,
255 interp: &'a Interpreter<'b>,
256 data_store: &'a crate::engine::arena::DataStore,
257 sheet_registry: &'a crate::engine::sheet_registry::SheetRegistry,
258 ) -> Self {
259 Self {
260 expr: ArgumentExpr::Arena {
261 id,
262 data_store,
263 sheet_registry,
264 },
265 interp,
266 cached_ast: std::cell::OnceCell::new(),
267 cached_ref: std::cell::OnceCell::new(),
268 }
269 }
270
271 pub fn value(&self) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
272 match &self.expr {
273 ArgumentExpr::Ast(node) => {
274 if let ASTNodeType::Literal(ref v) = node.node_type {
275 return Ok(crate::traits::CalcValue::Scalar(v.clone()));
276 }
277 self.interp.evaluate_ast(node)
278 }
279 ArgumentExpr::Arena {
280 id,
281 data_store,
282 sheet_registry,
283 } => self
284 .interp
285 .evaluate_arena_ast(*id, data_store, sheet_registry),
286 }
287 }
288
289 pub fn value_with_env(
290 &self,
291 env: crate::interpreter::LocalEnv,
292 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
293 let scoped = self.interp.with_local_env(env);
294 match &self.expr {
295 ArgumentExpr::Ast(node) => {
296 if let ASTNodeType::Literal(ref v) = node.node_type {
297 return Ok(crate::traits::CalcValue::Scalar(v.clone()));
298 }
299 scoped.evaluate_ast(node)
300 }
301 ArgumentExpr::Arena {
302 id,
303 data_store,
304 sheet_registry,
305 } => scoped.evaluate_arena_ast(*id, data_store, sheet_registry),
306 }
307 }
308
309 pub fn current_env(&self) -> crate::interpreter::LocalEnv {
310 self.interp.local_env().clone()
311 }
312
313 pub fn inline_array_literal(&self) -> Result<Option<Vec<Vec<LiteralValue>>>, ExcelError> {
314 match &self.expr {
315 ArgumentExpr::Ast(node) => match &node.node_type {
316 ASTNodeType::Literal(LiteralValue::Array(arr)) => Ok(Some(arr.clone())),
317 _ => Ok(None),
318 },
319 ArgumentExpr::Arena {
320 id,
321 data_store,
322 sheet_registry,
323 } => {
324 let node = data_store.get_node(*id).ok_or_else(|| {
325 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
326 })?;
327 match node {
328 crate::engine::arena::AstNodeData::Literal(vref) => {
329 match data_store.retrieve_value(*vref) {
330 LiteralValue::Array(arr) => Ok(Some(arr)),
331 _ => Ok(None),
332 }
333 }
334 _ => {
335 let _ = sheet_registry;
338 Ok(None)
339 }
340 }
341 }
342 }
343 }
344
345 fn reference_for_eval(&self) -> Result<ReferenceType, ExcelError> {
346 match &self.expr {
347 ArgumentExpr::Ast(node) => match &node.node_type {
348 ASTNodeType::Reference { reference, .. } => {
349 self.interp.reference_for_current_offset(reference)
350 }
351 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
352 self.interp.evaluate_ast_as_reference(node)
353 }
354 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
355 .with_message("Expected a reference (by-ref argument)")),
356 },
357 ArgumentExpr::Arena {
358 id,
359 data_store,
360 sheet_registry,
361 } => {
362 let node = data_store.get_node(*id).ok_or_else(|| {
363 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
364 })?;
365 match node {
366 crate::engine::arena::AstNodeData::Reference { ref_type, .. } => {
367 let reference = data_store
368 .reconstruct_reference_type_for_eval(ref_type, sheet_registry);
369 self.interp.reference_for_current_offset(&reference)
370 }
371 crate::engine::arena::AstNodeData::Function { .. }
372 | crate::engine::arena::AstNodeData::BinaryOp { .. } => self
373 .interp
374 .evaluate_arena_ast_as_reference(*id, data_store, sheet_registry),
375 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
376 .with_message("Expected a reference (by-ref argument)")),
377 }
378 }
379 }
380 }
381
382 pub fn range(&self) -> Result<Box<dyn Range>, ExcelError> {
383 match &self.expr {
384 ArgumentExpr::Ast(node) => match &node.node_type {
385 ASTNodeType::Reference { reference, .. } => {
386 let reference = self.interp.reference_for_current_offset(reference)?;
388 let view = self
389 .interp
390 .context
391 .resolve_range_view(&reference, self.interp.current_sheet())?;
392 let (rows, cols) = view.dims();
393 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
394 view.for_each_row(&mut |row| {
395 let row_data: Vec<LiteralValue> = (0..cols)
396 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
397 .collect();
398 out.push(row_data);
399 Ok(())
400 })?;
401 Ok(Box::new(InMemoryRange::new(out)))
402 }
403 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
404 let reference = self.reference_for_eval()?;
405 let view = self
406 .interp
407 .context
408 .resolve_range_view(&reference, self.interp.current_sheet())?;
409 let (rows, cols) = view.dims();
410 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
411 view.for_each_row(&mut |row| {
412 let row_data: Vec<LiteralValue> = (0..cols)
413 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
414 .collect();
415 out.push(row_data);
416 Ok(())
417 })?;
418 Ok(Box::new(InMemoryRange::new(out)))
419 }
420 ASTNodeType::Array(rows) => {
421 let mut materialized = Vec::new();
422 for row in rows {
423 let mut materialized_row = Vec::new();
424 for cell in row {
425 materialized_row.push(self.interp.evaluate_ast(cell)?.into_literal());
426 }
427 materialized.push(materialized_row);
428 }
429 Ok(Box::new(InMemoryRange::new(materialized)))
430 }
431 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
432 .with_message(format!("Expected a range, got {:?}", node.node_type))),
433 },
434 ArgumentExpr::Arena { id, data_store, .. } => {
435 let node = data_store.get_node(*id).ok_or_else(|| {
436 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
437 })?;
438
439 match node {
440 crate::engine::arena::AstNodeData::Reference { .. }
441 | crate::engine::arena::AstNodeData::Function { .. }
442 | crate::engine::arena::AstNodeData::BinaryOp { .. } => {
443 let reference = self.reference_for_eval()?;
444 let view = self
445 .interp
446 .context
447 .resolve_range_view(&reference, self.interp.current_sheet())?;
448 let (rows, cols) = view.dims();
449 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
450 view.for_each_row(&mut |row| {
451 let row_data: Vec<LiteralValue> = (0..cols)
452 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
453 .collect();
454 out.push(row_data);
455 Ok(())
456 })?;
457 Ok(Box::new(InMemoryRange::new(out)))
458 }
459 crate::engine::arena::AstNodeData::Array { .. } => {
460 let (rows, cols, elements) =
461 data_store.get_array_elems(*id).ok_or_else(|| {
462 ExcelError::new(ExcelErrorKind::Value).with_message("Invalid array")
463 })?;
464 let rows_usize = rows as usize;
465 let cols_usize = cols as usize;
466 let mut materialized: Vec<Vec<LiteralValue>> =
467 Vec::with_capacity(rows_usize);
468 for r in 0..rows_usize {
469 let mut row = Vec::with_capacity(cols_usize);
470 for c in 0..cols_usize {
471 let idx = r * cols_usize + c;
472 let elem_id = elements.get(idx).copied().ok_or_else(|| {
473 ExcelError::new(ExcelErrorKind::Value)
474 .with_message("Invalid array")
475 })?;
476 let v = self.interp.evaluate_arena_ast(
477 elem_id,
478 data_store,
479 self.sheet_registry(),
480 )?;
481 row.push(v.into_literal());
482 }
483 materialized.push(row);
484 }
485 Ok(Box::new(InMemoryRange::new(materialized)))
486 }
487 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
488 .with_message("Argument cannot be interpreted as a range.")),
489 }
490 }
491 }
492 }
493
494 fn sheet_registry(&self) -> &crate::engine::sheet_registry::SheetRegistry {
495 match &self.expr {
496 ArgumentExpr::Ast(_) => {
497 unreachable!("sheet_registry only used for arena ArgumentHandle")
499 }
500 ArgumentExpr::Arena { sheet_registry, .. } => sheet_registry,
501 }
502 }
503
504 pub fn range_view(&self) -> Result<RangeView<'b>, ExcelError> {
506 match &self.expr {
507 ArgumentExpr::Ast(node) => match &node.node_type {
508 ASTNodeType::Reference { reference, .. } => {
509 let reference = self.interp.reference_for_current_offset(reference)?;
510 self.interp
511 .context
512 .resolve_range_view(&reference, self.interp.current_sheet())
513 .map(|v| v.with_cancel_token(self.interp.context.cancellation_token()))
514 }
515 ASTNodeType::Literal(formualizer_common::LiteralValue::Array(arr)) => Ok(
517 RangeView::from_owned_rows(arr.clone(), self.interp.context.date_system())
518 .with_cancel_token(self.interp.context.cancellation_token()),
519 ),
520 ASTNodeType::Array(rows) => {
521 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows.len());
522 for r in rows {
523 let mut row_vals = Vec::with_capacity(r.len());
524 for cell in r {
525 row_vals.push(self.interp.evaluate_ast(cell)?.into_literal());
526 }
527 out.push(row_vals);
528 }
529 Ok(
530 RangeView::from_owned_rows(out, self.interp.context.date_system())
531 .with_cancel_token(self.interp.context.cancellation_token()),
532 )
533 }
534 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
535 let reference = self.reference_for_eval()?;
536 self.interp
537 .context
538 .resolve_range_view(&reference, self.interp.current_sheet())
539 .map(|v| v.with_cancel_token(self.interp.context.cancellation_token()))
540 }
541 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
542 .with_message("Argument cannot be interpreted as a range.")),
543 },
544 ArgumentExpr::Arena {
545 id,
546 data_store,
547 sheet_registry,
548 } => {
549 let node = data_store.get_node(*id).ok_or_else(|| {
550 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
551 })?;
552
553 match node {
554 crate::engine::arena::AstNodeData::Reference { .. }
555 | crate::engine::arena::AstNodeData::Function { .. }
556 | crate::engine::arena::AstNodeData::BinaryOp { .. } => {
557 let reference = self.reference_for_eval()?;
558 self.interp
559 .context
560 .resolve_range_view(&reference, self.interp.current_sheet())
561 .map(|v| v.with_cancel_token(self.interp.context.cancellation_token()))
562 }
563 crate::engine::arena::AstNodeData::Literal(vref) => {
564 match data_store.retrieve_value(*vref) {
565 LiteralValue::Array(arr) => Ok(RangeView::from_owned_rows(
566 arr,
567 self.interp.context.date_system(),
568 )
569 .with_cancel_token(self.interp.context.cancellation_token())),
570 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
571 .with_message("Argument cannot be interpreted as a range.")),
572 }
573 }
574 crate::engine::arena::AstNodeData::Array { .. } => {
575 let (rows, cols, elements) =
576 data_store.get_array_elems(*id).ok_or_else(|| {
577 ExcelError::new(ExcelErrorKind::Value).with_message("Invalid array")
578 })?;
579
580 let rows_usize = rows as usize;
581 let cols_usize = cols as usize;
582 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows_usize);
583 for r in 0..rows_usize {
584 let mut row = Vec::with_capacity(cols_usize);
585 for c in 0..cols_usize {
586 let idx = r * cols_usize + c;
587 let elem_id = elements.get(idx).copied().ok_or_else(|| {
588 ExcelError::new(ExcelErrorKind::Value)
589 .with_message("Invalid array")
590 })?;
591 let v = self.interp.evaluate_arena_ast(
592 elem_id,
593 data_store,
594 sheet_registry,
595 )?;
596 row.push(v.into_literal());
597 }
598 out.push(row);
599 }
600 Ok(
601 RangeView::from_owned_rows(out, self.interp.context.date_system())
602 .with_cancel_token(self.interp.context.cancellation_token()),
603 )
604 }
605 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
606 .with_message("Argument cannot be interpreted as a range.")),
607 }
608 }
609 }
610 }
611
612 pub fn value_or_range(&self) -> Result<EvaluatedArg<'_>, ExcelError> {
613 self.range().map(EvaluatedArg::Range).or_else(|_| {
614 self.value()
615 .map(|cv| EvaluatedArg::LiteralValue(Cow::Owned(cv.into_literal())))
616 })
617 }
618
619 pub fn lazy_values_owned(
624 &'a self,
625 ) -> Result<Box<dyn Iterator<Item = LiteralValue> + 'a>, ExcelError> {
626 match &self.expr {
627 ArgumentExpr::Ast(node) => match &node.node_type {
628 ASTNodeType::Reference { .. } => {
629 let view = self.range_view()?;
630 let mut values: Vec<LiteralValue> = Vec::new();
631 view.for_each_cell(&mut |v| {
632 values.push(v.clone());
633 Ok(())
634 })?;
635 Ok(Box::new(values.into_iter()))
636 }
637 ASTNodeType::Array(rows) => {
638 struct ArrayEvalIter<'a, 'b> {
639 rows: &'a [Vec<ASTNode>],
640 r: usize,
641 c: usize,
642 interp: &'a Interpreter<'b>,
643 }
644 impl<'a, 'b> Iterator for ArrayEvalIter<'a, 'b> {
645 type Item = LiteralValue;
646 fn next(&mut self) -> Option<Self::Item> {
647 if self.rows.is_empty() {
648 return None;
649 }
650 let rows = self.rows;
651 let mut r = self.r;
652 let mut c = self.c;
653 if r >= rows.len() {
654 return None;
655 }
656 let node = &rows[r][c];
657 c += 1;
659 if c >= rows[r].len() {
660 r += 1;
661 c = 0;
662 }
663 self.r = r;
664 self.c = c;
665 match self.interp.evaluate_ast(node) {
666 Ok(cv) => Some(cv.into_literal()),
667 Err(e) => Some(LiteralValue::Error(e)),
668 }
669 }
670 }
671 let it = ArrayEvalIter {
672 rows,
673 r: 0,
674 c: 0,
675 interp: self.interp,
676 };
677 Ok(Box::new(it))
678 }
679 _ => {
680 let v = self.value()?.into_literal();
682 Ok(Box::new(std::iter::once(v)))
683 }
684 },
685 ArgumentExpr::Arena {
686 id,
687 data_store,
688 sheet_registry,
689 } => {
690 let node = data_store.get_node(*id).ok_or_else(|| {
691 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
692 })?;
693
694 match node {
695 crate::engine::arena::AstNodeData::Reference { .. } => {
696 let view = self.range_view()?;
697 let mut values: Vec<LiteralValue> = Vec::new();
698 view.for_each_cell(&mut |v| {
699 values.push(v.clone());
700 Ok(())
701 })?;
702 Ok(Box::new(values.into_iter()))
703 }
704 crate::engine::arena::AstNodeData::Array { .. } => {
705 let (rows, cols, elements) =
706 data_store.get_array_elems(*id).ok_or_else(|| {
707 ExcelError::new(ExcelErrorKind::Value).with_message("Invalid array")
708 })?;
709
710 struct ArenaArrayEvalIter<'a, 'b> {
711 elements: &'a [crate::engine::arena::AstNodeId],
712 idx: usize,
713 interp: &'a Interpreter<'b>,
714 data_store: &'a crate::engine::arena::DataStore,
715 sheet_registry: &'a crate::engine::sheet_registry::SheetRegistry,
716 }
717
718 impl<'a, 'b> Iterator for ArenaArrayEvalIter<'a, 'b> {
719 type Item = LiteralValue;
720
721 fn next(&mut self) -> Option<Self::Item> {
722 let id = self.elements.get(self.idx).copied()?;
723 self.idx += 1;
724 match self.interp.evaluate_arena_ast(
725 id,
726 self.data_store,
727 self.sheet_registry,
728 ) {
729 Ok(cv) => Some(cv.into_literal()),
730 Err(e) => Some(LiteralValue::Error(e)),
731 }
732 }
733 }
734
735 let _ = (rows, cols);
736 let it = ArenaArrayEvalIter {
737 elements,
738 idx: 0,
739 interp: self.interp,
740 data_store,
741 sheet_registry,
742 };
743 Ok(Box::new(it))
744 }
745 _ => {
746 let v = self
747 .interp
748 .evaluate_arena_ast(*id, data_store, sheet_registry)?;
749 Ok(Box::new(std::iter::once(v.into_literal())))
750 }
751 }
752 }
753 }
754 }
755
756 pub fn ast(&self) -> &ASTNode {
757 match &self.expr {
758 ArgumentExpr::Ast(node) => node,
759 ArgumentExpr::Arena {
760 id,
761 data_store,
762 sheet_registry,
763 } => self.cached_ast.get_or_init(|| {
764 data_store
765 .retrieve_ast(*id, sheet_registry)
766 .unwrap_or_else(|| ASTNode {
767 node_type: ASTNodeType::Literal(LiteralValue::Error(
768 ExcelError::new(ExcelErrorKind::Value)
769 .with_message("Missing formula AST"),
770 )),
771 source_token: None,
772 contains_volatile: false,
773 })
774 }),
775 }
776 }
777
778 pub fn as_reference(&self) -> Result<&ReferenceType, ExcelError> {
781 match &self.expr {
782 ArgumentExpr::Ast(node) => match &node.node_type {
783 ASTNodeType::Reference { reference, .. } => Ok(reference),
784 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
785 .with_message("Expected a reference (by-ref argument)")),
786 },
787 ArgumentExpr::Arena { .. } => {
788 let reference = self.reference_for_eval()?;
789 Ok(self.cached_ref.get_or_init(|| reference))
790 }
791 }
792 }
793
794 pub fn as_reference_or_eval(&self) -> Result<ReferenceType, ExcelError> {
797 match &self.expr {
798 ArgumentExpr::Ast(node) => match &node.node_type {
799 ASTNodeType::Reference { reference, .. } => {
800 self.interp.reference_for_current_offset(reference)
801 }
802 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
803 self.interp.evaluate_ast_as_reference(node)
804 }
805 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
806 .with_message("Argument is not a reference")),
807 },
808 ArgumentExpr::Arena {
809 id,
810 data_store,
811 sheet_registry,
812 } => {
813 let node = data_store.get_node(*id).ok_or_else(|| {
814 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
815 })?;
816
817 match node {
818 crate::engine::arena::AstNodeData::Reference { .. } => {
819 self.reference_for_eval()
820 }
821 crate::engine::arena::AstNodeData::Function { .. }
822 | crate::engine::arena::AstNodeData::BinaryOp { .. } => self
823 .interp
824 .evaluate_arena_ast_as_reference(*id, data_store, sheet_registry),
825 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
826 .with_message("Argument is not a reference")),
827 }
828 }
829 }
830 }
831
832 pub fn matches_kind(&self, k: formualizer_common::ArgKind) -> Result<bool, ExcelError> {
834 Ok(match k {
835 formualizer_common::ArgKind::Any => true,
836 formualizer_common::ArgKind::Range => self.range().is_ok(),
837 formualizer_common::ArgKind::Number => matches!(
838 self.value()?.into_literal(),
839 LiteralValue::Number(_) | LiteralValue::Int(_)
840 ),
841 formualizer_common::ArgKind::Text => {
842 matches!(self.value()?.into_literal(), LiteralValue::Text(_))
843 }
844 formualizer_common::ArgKind::Logical => {
845 matches!(self.value()?.into_literal(), LiteralValue::Boolean(_))
846 }
847 })
848 }
849}
850
851#[derive(Debug, Clone)]
853pub struct InMemoryRange {
854 data: Vec<Vec<LiteralValue>>,
855}
856impl InMemoryRange {
857 pub fn new(d: Vec<Vec<LiteralValue>>) -> Self {
858 Self { data: d }
859 }
860}
861impl Range for InMemoryRange {
862 fn get(&self, r: usize, c: usize) -> Result<LiteralValue, ExcelError> {
863 Ok(self
864 .data
865 .get(r)
866 .and_then(|row| row.get(c))
867 .cloned()
868 .unwrap_or(LiteralValue::Empty))
869 }
870 fn dimensions(&self) -> (usize, usize) {
871 (self.data.len(), self.data.first().map_or(0, |r| r.len()))
872 }
873 fn as_any(&self) -> &dyn Any {
874 self
875 }
876}
877
878pub trait Table: Debug + Send + Sync {
881 fn get_cell(&self, row: usize, column: &str) -> Result<LiteralValue, ExcelError>;
882 fn get_column(&self, column: &str) -> Result<Box<dyn Range>, ExcelError>;
883 fn columns(&self) -> Vec<String> {
885 vec![]
886 }
887 fn data_height(&self) -> usize {
889 0
890 }
891 fn has_headers(&self) -> bool {
893 false
894 }
895 fn has_totals(&self) -> bool {
897 false
898 }
899 fn headers_row(&self) -> Option<Box<dyn Range>> {
901 None
902 }
903 fn totals_row(&self) -> Option<Box<dyn Range>> {
905 None
906 }
907 fn data_body(&self) -> Option<Box<dyn Range>> {
909 None
910 }
911 fn clone_box(&self) -> Box<dyn Table>;
912}
913impl Table for Box<dyn Table> {
914 fn get_cell(&self, r: usize, c: &str) -> Result<LiteralValue, ExcelError> {
915 (**self).get_cell(r, c)
916 }
917 fn get_column(&self, c: &str) -> Result<Box<dyn Range>, ExcelError> {
918 (**self).get_column(c)
919 }
920 fn columns(&self) -> Vec<String> {
921 (**self).columns()
922 }
923 fn data_height(&self) -> usize {
924 (**self).data_height()
925 }
926 fn has_headers(&self) -> bool {
927 (**self).has_headers()
928 }
929 fn has_totals(&self) -> bool {
930 (**self).has_totals()
931 }
932 fn headers_row(&self) -> Option<Box<dyn Range>> {
933 (**self).headers_row()
934 }
935 fn totals_row(&self) -> Option<Box<dyn Range>> {
936 (**self).totals_row()
937 }
938 fn data_body(&self) -> Option<Box<dyn Range>> {
939 (**self).data_body()
940 }
941 fn clone_box(&self) -> Box<dyn Table> {
942 (**self).clone_box()
943 }
944}
945
946pub trait ReferenceResolver: Send + Sync {
949 fn resolve_cell_reference(
950 &self,
951 sheet: Option<&str>,
952 row: u32,
953 col: u32,
954 ) -> Result<LiteralValue, ExcelError>;
955}
956pub trait RangeResolver: Send + Sync {
957 fn resolve_range_reference(
958 &self,
959 sheet: Option<&str>,
960 sr: Option<u32>,
961 sc: Option<u32>,
962 er: Option<u32>,
963 ec: Option<u32>,
964 ) -> Result<Box<dyn Range>, ExcelError>;
965}
966pub trait NamedRangeResolver: Send + Sync {
967 fn resolve_named_range_reference(
968 &self,
969 name: &str,
970 ) -> Result<Vec<Vec<LiteralValue>>, ExcelError>;
971}
972pub trait TableResolver: Send + Sync {
973 fn resolve_table_reference(
974 &self,
975 tref: &formualizer_parse::parser::TableReference,
976 ) -> Result<Box<dyn Table>, ExcelError>;
977}
978
979pub trait SourceResolver: Send + Sync {
980 fn source_scalar_version(&self, _name: &str) -> Option<u64> {
981 None
982 }
983
984 fn resolve_source_scalar(&self, name: &str) -> Result<LiteralValue, ExcelError> {
985 Err(ExcelError::new(ExcelErrorKind::NImpl)
986 .with_message(format!("Source scalar not supported: {name}")))
987 }
988
989 fn source_table_version(&self, _name: &str) -> Option<u64> {
990 None
991 }
992
993 fn resolve_source_table(&self, name: &str) -> Result<Box<dyn Table>, ExcelError> {
994 Err(ExcelError::new(ExcelErrorKind::NImpl)
995 .with_message(format!("Source table not supported: {name}")))
996 }
997}
998
999pub trait Resolver: ReferenceResolver + RangeResolver + NamedRangeResolver + TableResolver {
1000 fn resolve_range_like(&self, r: &ReferenceType) -> Result<Box<dyn Range>, ExcelError> {
1001 match r {
1002 ReferenceType::Range {
1003 sheet,
1004 start_row,
1005 start_col,
1006 end_row,
1007 end_col,
1008 ..
1009 } => self.resolve_range_reference(
1010 sheet.as_deref(),
1011 *start_row,
1012 *start_col,
1013 *end_row,
1014 *end_col,
1015 ),
1016 ReferenceType::External(_) => Err(ExcelError::new(ExcelErrorKind::NImpl)
1017 .with_message("External references are not supported by Resolver".to_string())),
1018 ReferenceType::Table(tref) => {
1019 let t = self.resolve_table_reference(tref)?;
1020 match &tref.specifier {
1021 Some(TableSpecifier::Column(c)) => t.get_column(c),
1022 Some(TableSpecifier::ColumnRange(start, end)) => {
1023 let cols = t.columns();
1025 let start_key = start.to_lowercase();
1026 let end_key = end.to_lowercase();
1027 let start_idx = cols.iter().position(|n| n.to_lowercase() == start_key);
1028 let end_idx = cols.iter().position(|n| n.to_lowercase() == end_key);
1029 if let (Some(mut si), Some(mut ei)) = (start_idx, end_idx) {
1030 if si > ei {
1031 std::mem::swap(&mut si, &mut ei);
1032 }
1033 let h = t.data_height();
1035 let w = ei - si + 1;
1036 let mut rows = vec![vec![LiteralValue::Empty; w]; h];
1037 for (offset, ci) in (si..=ei).enumerate() {
1038 let cname = &cols[ci];
1039 let col_range = t.get_column(cname)?;
1040 let (rh, _) = col_range.dimensions();
1041 for (r, row) in rows.iter_mut().enumerate().take(h.min(rh)) {
1042 row[offset] = col_range.get(r, 0)?;
1043 }
1044 }
1045 Ok(Box::new(InMemoryRange::new(rows)))
1046 } else {
1047 Err(ExcelError::new(ExcelErrorKind::Ref).with_message(
1048 "Column range refers to unknown column(s)".to_string(),
1049 ))
1050 }
1051 }
1052 Some(TableSpecifier::SpecialItem(
1053 formualizer_parse::parser::SpecialItem::Headers,
1054 )) => {
1055 if let Some(h) = t.headers_row() {
1056 Ok(h)
1057 } else {
1058 Ok(Box::new(InMemoryRange::new(vec![])))
1059 }
1060 }
1061 Some(TableSpecifier::SpecialItem(
1062 formualizer_parse::parser::SpecialItem::Totals,
1063 )) => {
1064 if let Some(tr) = t.totals_row() {
1065 Ok(tr)
1066 } else {
1067 Ok(Box::new(InMemoryRange::new(vec![])))
1068 }
1069 }
1070 Some(TableSpecifier::SpecialItem(
1071 formualizer_parse::parser::SpecialItem::Data,
1072 )) => {
1073 if let Some(body) = t.data_body() {
1074 Ok(body)
1075 } else {
1076 Ok(Box::new(InMemoryRange::new(vec![])))
1077 }
1078 }
1079 Some(TableSpecifier::SpecialItem(
1080 formualizer_parse::parser::SpecialItem::All,
1081 )) => {
1082 let mut out: Vec<Vec<LiteralValue>> = Vec::new();
1084 if let Some(h) = t.headers_row() {
1085 out.extend(h.iter_rows());
1086 }
1087 if let Some(body) = t.data_body() {
1088 out.extend(body.iter_rows());
1089 }
1090 if let Some(tr) = t.totals_row() {
1091 out.extend(tr.iter_rows());
1092 }
1093 Ok(Box::new(InMemoryRange::new(out)))
1094 }
1095 Some(TableSpecifier::SpecialItem(
1096 formualizer_parse::parser::SpecialItem::ThisRow,
1097 )) => Err(ExcelError::new(ExcelErrorKind::NImpl).with_message(
1098 "@ (This Row) requires table-aware context; not yet supported".to_string(),
1099 )),
1100 Some(TableSpecifier::All) => {
1101 let mut out: Vec<Vec<LiteralValue>> = Vec::new();
1103 if let Some(h) = t.headers_row() {
1104 out.extend(h.iter_rows());
1105 }
1106 if let Some(body) = t.data_body() {
1107 out.extend(body.iter_rows());
1108 }
1109 if let Some(tr) = t.totals_row() {
1110 out.extend(tr.iter_rows());
1111 }
1112 Ok(Box::new(InMemoryRange::new(out)))
1113 }
1114 Some(TableSpecifier::Data) => {
1115 if let Some(body) = t.data_body() {
1116 Ok(body)
1117 } else {
1118 Ok(Box::new(InMemoryRange::new(vec![])))
1119 }
1120 }
1121 Some(TableSpecifier::Combination(_)) => Err(ExcelError::new(
1123 ExcelErrorKind::NImpl,
1124 )
1125 .with_message("Complex structured references not yet supported".to_string())),
1126 Some(TableSpecifier::Row(_)) => Err(ExcelError::new(ExcelErrorKind::NImpl)
1127 .with_message("Row selectors (@/index) not yet supported".to_string())),
1128 Some(TableSpecifier::Headers) | Some(TableSpecifier::Totals) => {
1129 Err(ExcelError::new(ExcelErrorKind::NImpl).with_message(
1130 "Legacy Headers/Totals variants not used; use SpecialItem".to_string(),
1131 ))
1132 }
1133 None => Err(ExcelError::new(ExcelErrorKind::Ref).with_message(
1134 "Table reference without specifier is unsupported".to_string(),
1135 )),
1136 }
1137 }
1138 ReferenceType::NamedRange(n) => {
1139 let v = self.resolve_named_range_reference(n)?;
1140 Ok(Box::new(InMemoryRange::new(v)))
1141 }
1142 ReferenceType::Cell {
1143 sheet, row, col, ..
1144 } => {
1145 let v = self.resolve_cell_reference(sheet.as_deref(), *row, *col)?;
1146 Ok(Box::new(InMemoryRange::new(vec![vec![v]])))
1147 }
1148 ReferenceType::Cell3D { .. } | ReferenceType::Range3D { .. } => {
1149 Err(ExcelError::new(ExcelErrorKind::NImpl)
1150 .with_message("3D references are not yet supported".to_string()))
1151 }
1152 }
1153 }
1154}
1155
1156pub trait FunctionProvider: Send + Sync {
1159 fn get_function(&self, ns: &str, name: &str) -> Option<Arc<dyn Function>>;
1160}
1161
1162pub trait EvaluationContext: Resolver + FunctionProvider + SourceResolver {
1163 fn thread_pool(&self) -> Option<&Arc<rayon::ThreadPool>> {
1166 None
1167 }
1168
1169 fn cancellation_token(&self) -> Option<Arc<std::sync::atomic::AtomicBool>> {
1171 None
1172 }
1173
1174 fn chunk_hint(&self) -> Option<usize> {
1176 None
1177 }
1178
1179 fn resolve_range_view<'c>(
1182 &'c self,
1183 _reference: &ReferenceType,
1184 _current_sheet: &str,
1185 ) -> Result<RangeView<'c>, ExcelError> {
1186 Err(ExcelError::new(ExcelErrorKind::NImpl))
1187 }
1188
1189 fn resolve_cell_reference_value(
1194 &self,
1195 sheet: Option<&str>,
1196 row: u32,
1197 col: u32,
1198 current_sheet: &str,
1199 ) -> Result<LiteralValue, ExcelError> {
1200 let reference = ReferenceType::Cell {
1201 sheet: sheet.map(str::to_string),
1202 row,
1203 col,
1204 row_abs: true,
1205 col_abs: true,
1206 };
1207 let view = self.resolve_range_view(&reference, current_sheet)?;
1208 Ok(view.as_1x1().unwrap_or(LiteralValue::Empty))
1209 }
1210
1211 fn locale(&self) -> crate::locale::Locale {
1213 crate::locale::Locale::invariant()
1214 }
1215
1216 fn workbook_sheet_count(&self) -> Option<usize> {
1218 None
1219 }
1220
1221 fn sheet_index_by_name(&self, _sheet: &str) -> Option<usize> {
1223 None
1224 }
1225
1226 fn current_sheet_index(&self, current_sheet: &str) -> Option<usize> {
1228 self.sheet_index_by_name(current_sheet)
1229 }
1230
1231 fn inspect_reference(
1233 &self,
1234 _reference: &ReferenceType,
1235 _current_sheet: &str,
1236 ) -> Result<Option<ReferenceInfo>, ExcelError> {
1237 Ok(None)
1238 }
1239
1240 fn formula_text_at_cell(&self, _cell: CellRef) -> Result<Option<String>, ExcelError> {
1242 Ok(None)
1243 }
1244
1245 fn clock(&self) -> &dyn crate::timezone::ClockProvider {
1254 #[cfg(feature = "system-clock")]
1255 {
1256 static DEFAULT_CLOCK: std::sync::OnceLock<crate::timezone::SystemClock> =
1257 std::sync::OnceLock::new();
1258 DEFAULT_CLOCK.get_or_init(|| {
1259 crate::timezone::SystemClock::new(crate::timezone::TimeZoneSpec::default())
1260 })
1261 }
1262 #[cfg(not(feature = "system-clock"))]
1263 {
1264 static DEFAULT_CLOCK: std::sync::OnceLock<crate::timezone::FixedClock> =
1265 std::sync::OnceLock::new();
1266 DEFAULT_CLOCK.get_or_init(|| {
1267 crate::timezone::FixedClock::new(
1268 chrono::DateTime::UNIX_EPOCH,
1269 crate::timezone::TimeZoneSpec::Utc,
1270 )
1271 })
1272 }
1273 }
1274
1275 fn timezone(&self) -> &crate::timezone::TimeZoneSpec {
1279 self.clock().timezone()
1280 }
1281
1282 fn volatile_level(&self) -> VolatileLevel {
1284 VolatileLevel::Always
1285 }
1286
1287 fn workbook_seed(&self) -> u64 {
1289 0xF0F0_D0D0_AAAA_5555
1290 }
1291
1292 fn recalc_epoch(&self) -> u64 {
1294 0
1295 }
1296
1297 fn used_rows_for_columns(
1302 &self,
1303 _sheet: &str,
1304 _start_col: u32,
1305 _end_col: u32,
1306 ) -> Option<(u32, u32)> {
1307 None
1308 }
1309
1310 fn used_cols_for_rows(
1313 &self,
1314 _sheet: &str,
1315 _start_row: u32,
1316 _end_row: u32,
1317 ) -> Option<(u32, u32)> {
1318 None
1319 }
1320
1321 fn sheet_bounds(&self, _sheet: &str) -> Option<(u32, u32)> {
1323 None
1324 }
1325
1326 fn data_snapshot_id(&self) -> u64 {
1328 0
1329 }
1330
1331 fn backend_caps(&self) -> BackendCaps {
1333 BackendCaps::default()
1334 }
1335
1336 fn date_system(&self) -> crate::engine::DateSystem {
1341 crate::engine::DateSystem::Excel1900
1342 }
1343
1344 fn build_lookup_index(
1347 &self,
1348 _view: &RangeView<'_>,
1349 _axis: LookupAxis,
1350 ) -> Option<std::sync::Arc<LookupIndex>> {
1351 None
1352 }
1353
1354 fn build_criteria_mask(
1357 &self,
1358 _view: &RangeView<'_>,
1359 _col_in_view: usize,
1360 _pred: &crate::args::CriteriaPredicate,
1361 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1362 None
1363 }
1364
1365 fn build_row_visibility_mask(
1368 &self,
1369 _view: &RangeView<'_>,
1370 _mode: VisibilityMaskMode,
1371 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1372 None
1373 }
1374}
1375
1376#[derive(Copy, Clone, Debug, Default)]
1378pub struct BackendCaps {
1379 pub streaming: bool,
1381 pub used_region: bool,
1383 pub write: bool,
1385 pub tables: bool,
1387 pub async_stream: bool,
1389}
1390
1391#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1394pub enum VolatileLevel {
1395 Always,
1397 OnRecalc,
1399 OnOpen,
1401}
1402
1403pub trait FunctionContext<'ctx> {
1405 fn locale(&self) -> crate::locale::Locale;
1406 fn timezone(&self) -> &crate::timezone::TimeZoneSpec;
1407 fn clock(&self) -> &dyn crate::timezone::ClockProvider;
1408 fn thread_pool(&self) -> Option<&std::sync::Arc<rayon::ThreadPool>>;
1409 fn cancellation_token(&self) -> Option<Arc<std::sync::atomic::AtomicBool>>;
1410 fn chunk_hint(&self) -> Option<usize>;
1411
1412 fn current_sheet(&self) -> &str;
1414
1415 fn workbook_sheet_count(&self) -> Option<usize> {
1416 None
1417 }
1418
1419 fn sheet_index_by_name(&self, _sheet: &str) -> Option<usize> {
1420 None
1421 }
1422
1423 fn current_sheet_index(&self) -> Option<usize> {
1424 self.sheet_index_by_name(self.current_sheet())
1425 }
1426
1427 fn inspect_reference(
1428 &self,
1429 _reference: &ReferenceType,
1430 ) -> Result<Option<ReferenceInfo>, ExcelError> {
1431 Ok(None)
1432 }
1433
1434 fn formula_text_at_cell(&self, _cell: CellRef) -> Result<Option<String>, ExcelError> {
1435 Ok(None)
1436 }
1437
1438 fn volatile_level(&self) -> VolatileLevel;
1439 fn workbook_seed(&self) -> u64;
1440 fn recalc_epoch(&self) -> u64;
1441 fn current_cell(&self) -> Option<CellRef>;
1442
1443 fn resolve_range_view(
1445 &self,
1446 _reference: &ReferenceType,
1447 _current_sheet: &str,
1448 ) -> Result<RangeView<'ctx>, ExcelError>;
1449
1450 fn rng_for_current(&self, fn_salt: u64) -> rand::rngs::SmallRng {
1454 use crate::rng::{compose_seed, small_rng_from_lanes};
1455 let (sheet_id, row, col) = self
1456 .current_cell()
1457 .map(|c| (c.sheet_id as u32, c.coord.row(), c.coord.col()))
1458 .unwrap_or((0, 0, 0));
1459 let epoch = match self.volatile_level() {
1461 VolatileLevel::OnRecalc => self.recalc_epoch(),
1462 _ => 0,
1463 };
1464 let (l0, l1) = compose_seed(self.workbook_seed(), sheet_id, row, col, fn_salt, epoch);
1465 small_rng_from_lanes(l0, l1)
1466 }
1467
1468 fn date_system(&self) -> crate::engine::DateSystem {
1470 crate::engine::DateSystem::Excel1900
1471 }
1472
1473 fn get_lookup_index(
1476 &self,
1477 _view: &RangeView<'_>,
1478 _axis: LookupAxis,
1479 ) -> Option<std::sync::Arc<LookupIndex>> {
1480 None
1481 }
1482
1483 fn get_criteria_mask(
1486 &self,
1487 _view: &RangeView<'_>,
1488 _col_in_view: usize,
1489 _pred: &crate::args::CriteriaPredicate,
1490 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1491 None
1492 }
1493
1494 fn get_row_visibility_mask(
1496 &self,
1497 _view: &RangeView<'_>,
1498 _mode: VisibilityMaskMode,
1499 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1500 None
1501 }
1502}
1503
1504pub struct DefaultFunctionContext<'a> {
1506 pub base: &'a dyn EvaluationContext,
1507 pub current: Option<CellRef>,
1508 pub current_sheet: &'a str,
1509}
1510
1511impl<'a> DefaultFunctionContext<'a> {
1512 pub fn new(
1513 base: &'a dyn EvaluationContext,
1514 current: Option<CellRef>,
1515 current_sheet: &'a str,
1516 ) -> Self {
1517 Self {
1518 base,
1519 current,
1520 current_sheet,
1521 }
1522 }
1523
1524 pub fn new_with_sheet(
1525 base: &'a dyn EvaluationContext,
1526 current: Option<CellRef>,
1527 current_sheet: &'a str,
1528 ) -> Self {
1529 Self::new(base, current, current_sheet)
1530 }
1531}
1532
1533impl<'a> FunctionContext<'a> for DefaultFunctionContext<'a> {
1534 fn locale(&self) -> crate::locale::Locale {
1535 self.base.locale()
1536 }
1537
1538 fn current_sheet(&self) -> &str {
1539 self.current_sheet
1540 }
1541
1542 fn workbook_sheet_count(&self) -> Option<usize> {
1543 self.base.workbook_sheet_count()
1544 }
1545
1546 fn sheet_index_by_name(&self, sheet: &str) -> Option<usize> {
1547 self.base.sheet_index_by_name(sheet)
1548 }
1549
1550 fn current_sheet_index(&self) -> Option<usize> {
1551 self.base.current_sheet_index(self.current_sheet)
1552 }
1553
1554 fn inspect_reference(
1555 &self,
1556 reference: &ReferenceType,
1557 ) -> Result<Option<ReferenceInfo>, ExcelError> {
1558 self.base.inspect_reference(reference, self.current_sheet)
1559 }
1560
1561 fn formula_text_at_cell(&self, cell: CellRef) -> Result<Option<String>, ExcelError> {
1562 self.base.formula_text_at_cell(cell)
1563 }
1564
1565 fn timezone(&self) -> &crate::timezone::TimeZoneSpec {
1566 self.base.timezone()
1567 }
1568
1569 fn clock(&self) -> &dyn crate::timezone::ClockProvider {
1570 self.base.clock()
1571 }
1572 fn thread_pool(&self) -> Option<&std::sync::Arc<rayon::ThreadPool>> {
1573 self.base.thread_pool()
1574 }
1575 fn cancellation_token(&self) -> Option<Arc<std::sync::atomic::AtomicBool>> {
1576 self.base.cancellation_token()
1577 }
1578 fn chunk_hint(&self) -> Option<usize> {
1579 self.base.chunk_hint()
1580 }
1581
1582 fn volatile_level(&self) -> VolatileLevel {
1583 self.base.volatile_level()
1584 }
1585 fn workbook_seed(&self) -> u64 {
1586 self.base.workbook_seed()
1587 }
1588 fn recalc_epoch(&self) -> u64 {
1589 self.base.recalc_epoch()
1590 }
1591 fn current_cell(&self) -> Option<CellRef> {
1592 self.current
1593 }
1594
1595 fn resolve_range_view(
1596 &self,
1597 reference: &ReferenceType,
1598 current_sheet: &str,
1599 ) -> Result<RangeView<'a>, ExcelError> {
1600 self.base.resolve_range_view(reference, current_sheet)
1601 }
1602
1603 fn date_system(&self) -> crate::engine::DateSystem {
1606 self.base.date_system()
1607 }
1608
1609 fn get_lookup_index(
1610 &self,
1611 view: &RangeView<'_>,
1612 axis: LookupAxis,
1613 ) -> Option<std::sync::Arc<LookupIndex>> {
1614 self.base.build_lookup_index(view, axis)
1615 }
1616
1617 fn get_criteria_mask(
1618 &self,
1619 view: &RangeView<'_>,
1620 col_in_view: usize,
1621 pred: &crate::args::CriteriaPredicate,
1622 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1623 self.base.build_criteria_mask(view, col_in_view, pred)
1624 }
1625
1626 fn get_row_visibility_mask(
1627 &self,
1628 view: &RangeView<'_>,
1629 mode: VisibilityMaskMode,
1630 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1631 self.base.build_row_visibility_mask(view, mode)
1632 }
1633}