1use super::compiled::CompiledLogic;
2use super::config::RLogicConfig;
3use index::TableIndex;
4use serde_json::Value;
5use std::cell::UnsafeCell;
6use std::collections::HashMap;
7use std::sync::RwLock;
8
9pub mod arithmetic;
10pub mod array_lookup;
11pub mod array_ops;
12pub mod comparison;
13pub mod date_ops;
14pub mod helpers;
15pub mod index;
16pub mod logical;
17pub mod math_ops;
18pub mod optimizations;
19pub mod string_ops;
20pub mod types;
21
22pub use helpers::*;
23pub use types::*;
24
25pub(crate) struct TableScope {
32 pub path: String,
34 pub rows: *const Vec<Value>,
36 pub current_row: Option<usize>,
38}
39
40unsafe impl Send for TableScope {}
44unsafe impl Send for Evaluator {}
45unsafe impl Sync for Evaluator {}
46
47pub struct TableScopeGuard<'a> {
49 evaluator: &'a Evaluator,
50}
51
52impl<'a> Drop for TableScopeGuard<'a> {
53 fn drop(&mut self) {
54 unsafe {
56 *self.evaluator.table_scope.get() = None;
57 }
58 }
59}
60
61pub struct Evaluator {
72 config: RLogicConfig,
73 indices: RwLock<HashMap<String, TableIndex>>,
75 static_arrays: Option<std::sync::Arc<indexmap::IndexMap<String, std::sync::Arc<Value>>>>,
77 pub(crate) table_scope: UnsafeCell<Option<TableScope>>,
79}
80
81impl Evaluator {
82 pub fn new() -> Self {
83 Self {
84 config: RLogicConfig::default(),
85 indices: RwLock::new(HashMap::new()),
86 static_arrays: None,
87 table_scope: UnsafeCell::new(None),
88 }
89 }
90
91 pub(crate) fn enter_table_scope<'a>(
99 &'a self,
100 path: String,
101 rows: &Vec<Value>,
102 ) -> TableScopeGuard<'a> {
103 unsafe {
105 *self.table_scope.get() = Some(TableScope {
106 path,
107 rows: rows as *const Vec<Value>,
108 current_row: None,
109 });
110 }
111 TableScopeGuard { evaluator: self }
112 }
113
114 pub(crate) fn update_table_scope_rows(&self, rows: &Vec<Value>) {
116 unsafe {
118 if let Some(ts) = (*self.table_scope.get()).as_mut() {
119 ts.rows = rows as *const Vec<Value>;
120 }
121 }
122 }
123
124 pub(crate) fn set_table_scope_row(&self, row_idx: Option<usize>) {
126 unsafe {
128 if let Some(ts) = (*self.table_scope.get()).as_mut() {
129 ts.current_row = row_idx;
130 }
131 }
132 }
133
134 pub fn with_config(mut self, config: RLogicConfig) -> Self {
135 self.config = config;
136 self
137 }
138
139 pub fn set_static_arrays(
141 &mut self,
142 static_arrays: std::sync::Arc<indexmap::IndexMap<String, std::sync::Arc<Value>>>,
143 ) {
144 self.static_arrays = Some(static_arrays);
145 }
146
147 pub fn index_table(&self, name: &str, data: &Value) {
149 if let Some(index) = TableIndex::new(data) {
150 if let Ok(mut indices) = self.indices.write() {
151 indices.insert(name.to_string(), index);
152 }
153 }
154 }
155
156 pub fn clear_indices(&self) {
158 if let Ok(mut indices) = self.indices.write() {
159 indices.clear();
160 }
161 }
162
163 #[inline]
166 pub fn evaluate(&self, logic: &CompiledLogic, data: &Value) -> Result<Value, String> {
167 match logic {
169 CompiledLogic::Null => return Ok(Value::Null),
170 CompiledLogic::Bool(b) => return Ok(Value::Bool(*b)),
171 CompiledLogic::Number(n) => {
172 return Ok(self.f64_to_json(*n));
173 }
174 CompiledLogic::String(s) => return Ok(Value::String(s.clone())),
175 CompiledLogic::Var(name, None) if !name.is_empty() => {
176 return self.eval_var_or_default(name, &None, data, &Value::Null, 0);
178 }
179 CompiledLogic::Ref(path, None) if !path.is_empty() => {
180 return self.eval_var_or_default(path, &None, data, &Value::Null, 0);
182 }
183 CompiledLogic::Add(items) if items.len() <= 5 => {
185 if let Some(result) =
186 self.eval_arithmetic_fast(ArithOp::Add, items, data, &Value::Null)
187 {
188 return Ok(result);
189 }
190 }
191 CompiledLogic::Subtract(items) if items.len() <= 5 => {
192 if let Some(result) =
193 self.eval_arithmetic_fast(ArithOp::Sub, items, data, &Value::Null)
194 {
195 return Ok(result);
196 }
197 }
198 CompiledLogic::Multiply(items) if items.len() <= 5 => {
199 if let Some(result) =
200 self.eval_arithmetic_fast(ArithOp::Mul, items, data, &Value::Null)
201 {
202 return Ok(result);
203 }
204 }
205 CompiledLogic::Divide(items) if items.len() <= 5 => {
206 if let Some(result) =
207 self.eval_arithmetic_fast(ArithOp::Div, items, data, &Value::Null)
208 {
209 return Ok(result);
210 }
211 }
212 _ => {}
213 }
214
215 self.evaluate_with_context(logic, data, &Value::Null, 0)
217 }
218
219 #[inline]
230 pub fn evaluate_with_internal_context(
231 &self,
232 logic: &CompiledLogic,
233 user_data: &Value,
234 internal_context: &Value,
235 ) -> Result<Value, String> {
236 self.evaluate_with_context(logic, user_data, internal_context, 0)
237 }
238
239 fn evaluate_with_context(
247 &self,
248 logic: &CompiledLogic,
249 user_data: &Value,
250 internal_context: &Value,
251 depth: usize,
252 ) -> Result<Value, String> {
253 if depth > self.config.recursion_limit {
255 return Err("Recursion limit exceeded".to_string());
256 }
257
258 match logic {
259 CompiledLogic::Null => Ok(Value::Null),
261 CompiledLogic::Bool(b) => Ok(Value::Bool(*b)),
262 CompiledLogic::Number(n) => Ok(self.f64_to_json(*n)),
263 CompiledLogic::String(s) => Ok(Value::String(s.clone())),
264 CompiledLogic::Array(arr) => {
265 let results: Result<Vec<_>, _> = arr
266 .iter()
267 .map(|item| {
268 self.evaluate_with_context(item, user_data, internal_context, depth + 1)
269 })
270 .collect();
271 Ok(Value::Array(results?))
272 }
273
274 CompiledLogic::Var(name, default) => {
276 self.eval_var_or_default(name, default, user_data, internal_context, depth)
277 }
278
279 CompiledLogic::Ref(path, default) => {
280 self.eval_var_or_default(path, default, user_data, internal_context, depth)
281 }
282
283 CompiledLogic::And(items) => {
285 self.eval_and_or(items, true, user_data, internal_context, depth)
286 }
287 CompiledLogic::Or(items) => {
288 self.eval_and_or(items, false, user_data, internal_context, depth)
289 }
290 CompiledLogic::Not(expr) => {
291 let result =
292 self.evaluate_with_context(expr, user_data, internal_context, depth + 1)?;
293 Ok(Value::Bool(!is_truthy(&result)))
294 }
295 CompiledLogic::If(cond, then_expr, else_expr) => {
296 let condition =
297 self.evaluate_with_context(cond, user_data, internal_context, depth + 1)?;
298 if is_truthy(&condition) {
299 self.evaluate_with_context(then_expr, user_data, internal_context, depth + 1)
300 } else {
301 self.evaluate_with_context(else_expr, user_data, internal_context, depth + 1)
302 }
303 }
304
305 CompiledLogic::Equal(a, b) => {
307 self.eval_binary_compare(CompOp::Eq, a, b, user_data, internal_context, depth)
308 }
309 CompiledLogic::StrictEqual(a, b) => {
310 self.eval_binary_compare(CompOp::StrictEq, a, b, user_data, internal_context, depth)
311 }
312 CompiledLogic::NotEqual(a, b) => {
313 self.eval_binary_compare(CompOp::Ne, a, b, user_data, internal_context, depth)
314 }
315 CompiledLogic::StrictNotEqual(a, b) => {
316 self.eval_binary_compare(CompOp::StrictNe, a, b, user_data, internal_context, depth)
317 }
318 CompiledLogic::LessThan(a, b) => {
319 self.eval_binary_compare(CompOp::Lt, a, b, user_data, internal_context, depth)
320 }
321 CompiledLogic::LessThanOrEqual(a, b) => {
322 self.eval_binary_compare(CompOp::Le, a, b, user_data, internal_context, depth)
323 }
324 CompiledLogic::GreaterThan(a, b) => {
325 self.eval_binary_compare(CompOp::Gt, a, b, user_data, internal_context, depth)
326 }
327 CompiledLogic::GreaterThanOrEqual(a, b) => {
328 self.eval_binary_compare(CompOp::Ge, a, b, user_data, internal_context, depth)
329 }
330
331 CompiledLogic::Add(items) => self.eval_array_fold(
333 items,
334 0.0,
335 |acc, n| Some(acc + n),
336 user_data,
337 internal_context,
338 depth,
339 ),
340 CompiledLogic::Subtract(items) => {
341 if items.is_empty() {
342 return Ok(self.f64_to_json(0.0));
343 }
344 let first =
345 self.evaluate_with_context(&items[0], user_data, internal_context, depth + 1)?;
346 let mut result = to_f64(&first);
347
348 if items.len() == 1 {
349 return Ok(self.f64_to_json(-result));
350 }
351
352 for item in &items[1..] {
353 let val =
354 self.evaluate_with_context(item, user_data, internal_context, depth + 1)?;
355 result -= to_f64(&val);
356 }
357 Ok(self.f64_to_json(result))
358 }
359 CompiledLogic::Multiply(items) => {
360 if items.is_empty() {
362 return Ok(self.f64_to_json(0.0));
363 }
364 self.eval_array_fold(
365 items,
366 1.0,
367 |acc, n| Some(acc * n),
368 user_data,
369 internal_context,
370 depth,
371 )
372 }
373 CompiledLogic::Divide(items) => {
374 if items.is_empty() {
375 return Ok(self.f64_to_json(0.0_f64));
376 }
377 let first =
378 self.evaluate_with_context(&items[0], user_data, internal_context, depth + 1)?;
379 let mut result = to_f64(&first);
380
381 for item in &items[1..] {
382 let val =
383 self.evaluate_with_context(item, user_data, internal_context, depth + 1)?;
384 let divisor = to_f64(&val);
385 if divisor == 0.0 {
386 return Ok(Value::Null);
387 }
388 result /= divisor;
389 }
390 Ok(self.f64_to_json(result))
391 }
392 CompiledLogic::Modulo(a, b) => self.eval_binary_arith(
393 a,
394 b,
395 |a, b| if b == 0.0 { None } else { Some(a % b) },
396 user_data,
397 internal_context,
398 depth,
399 ),
400 CompiledLogic::Power(a, b) => self.eval_binary_arith(
401 a,
402 b,
403 |a, b| Some(a.powf(b)),
404 user_data,
405 internal_context,
406 depth,
407 ),
408
409 CompiledLogic::Map(array_expr, logic_expr) => {
411 self.eval_map(array_expr, logic_expr, user_data, internal_context, depth)
412 }
413 CompiledLogic::Filter(array_expr, logic_expr) => {
414 self.eval_filter(array_expr, logic_expr, user_data, internal_context, depth)
415 }
416 CompiledLogic::Reduce(array_expr, logic_expr, initial_expr) => self.eval_reduce(
417 array_expr,
418 logic_expr,
419 initial_expr,
420 user_data,
421 internal_context,
422 depth,
423 ),
424 CompiledLogic::All(array_expr, logic_expr) => self.eval_quantifier(
425 Quantifier::All,
426 array_expr,
427 logic_expr,
428 user_data,
429 internal_context,
430 depth,
431 ),
432 CompiledLogic::Some(array_expr, logic_expr) => self.eval_quantifier(
433 Quantifier::Some,
434 array_expr,
435 logic_expr,
436 user_data,
437 internal_context,
438 depth,
439 ),
440 CompiledLogic::None(array_expr, logic_expr) => self.eval_quantifier(
441 Quantifier::None,
442 array_expr,
443 logic_expr,
444 user_data,
445 internal_context,
446 depth,
447 ),
448 CompiledLogic::Merge(items) => {
449 self.eval_merge(items, user_data, internal_context, depth)
450 }
451 CompiledLogic::In(value_expr, array_expr) => {
452 self.eval_in(value_expr, array_expr, user_data, internal_context, depth)
453 }
454 CompiledLogic::Sum(array_expr, field_expr, threshold_expr) => self.eval_sum(
455 array_expr,
456 field_expr,
457 threshold_expr,
458 user_data,
459 internal_context,
460 depth,
461 ),
462 CompiledLogic::For(start_expr, end_expr, logic_expr) => self.eval_for(
463 start_expr,
464 end_expr,
465 logic_expr,
466 user_data,
467 internal_context,
468 depth,
469 ),
470 CompiledLogic::Multiplies(items) => {
471 self.eval_multiplies(items, user_data, internal_context, depth)
472 }
473 CompiledLogic::Divides(items) => {
474 self.eval_divides(items, user_data, internal_context, depth)
475 }
476
477 CompiledLogic::ValueAt(table_expr, row_idx_expr, col_name_expr) => self.eval_valueat(
479 table_expr,
480 row_idx_expr,
481 col_name_expr,
482 user_data,
483 internal_context,
484 depth,
485 ),
486 CompiledLogic::MaxAt(table_expr, col_name_expr) => self.eval_maxat(
487 table_expr,
488 col_name_expr,
489 user_data,
490 internal_context,
491 depth,
492 ),
493 CompiledLogic::IndexAt(lookup_expr, table_expr, field_expr, range_expr) => self
494 .eval_indexat(
495 lookup_expr,
496 table_expr,
497 field_expr,
498 range_expr,
499 user_data,
500 internal_context,
501 depth,
502 ),
503 CompiledLogic::Match(table_expr, conditions) => {
504 self.eval_match(table_expr, conditions, user_data, internal_context, depth)
505 }
506 CompiledLogic::MatchRange(table_expr, conditions) => {
507 self.eval_matchrange(table_expr, conditions, user_data, internal_context, depth)
508 }
509 CompiledLogic::Choose(table_expr, conditions) => {
510 self.eval_choose(table_expr, conditions, user_data, internal_context, depth)
511 }
512 CompiledLogic::FindIndex(table_expr, conditions) => {
513 self.eval_findindex(table_expr, conditions, user_data, internal_context, depth)
514 }
515
516 CompiledLogic::Cat(items) => {
518 self.concat_strings(items, user_data, internal_context, depth)
519 }
520 CompiledLogic::Substr(string_expr, start_expr, length_expr) => self.eval_substr(
521 string_expr,
522 start_expr,
523 length_expr,
524 user_data,
525 internal_context,
526 depth,
527 ),
528 CompiledLogic::Search(find_expr, within_expr, start_expr) => self.eval_search(
529 find_expr,
530 within_expr,
531 start_expr,
532 user_data,
533 internal_context,
534 depth,
535 ),
536 CompiledLogic::Left(text_expr, num_expr) => self.extract_text_side(
537 text_expr,
538 num_expr.as_deref(),
539 true,
540 user_data,
541 internal_context,
542 depth,
543 ),
544 CompiledLogic::Right(text_expr, num_expr) => self.extract_text_side(
545 text_expr,
546 num_expr.as_deref(),
547 false,
548 user_data,
549 internal_context,
550 depth,
551 ),
552 CompiledLogic::Mid(text_expr, start_expr, num_expr) => self.eval_mid(
553 text_expr,
554 start_expr,
555 num_expr,
556 user_data,
557 internal_context,
558 depth,
559 ),
560 CompiledLogic::SplitText(value_expr, sep_expr, index_expr) => self.eval_split_text(
561 value_expr,
562 sep_expr,
563 index_expr,
564 user_data,
565 internal_context,
566 depth,
567 ),
568 CompiledLogic::Concat(items) => {
569 self.concat_strings(items, user_data, internal_context, depth)
570 }
571 CompiledLogic::SplitValue(string_expr, sep_expr) => {
572 self.eval_split_value(string_expr, sep_expr, user_data, internal_context, depth)
573 }
574 CompiledLogic::StringFormat(value_expr, decimals, prefix, suffix, thousands_sep) => {
575 self.eval_string_format(
576 value_expr,
577 decimals,
578 prefix,
579 suffix,
580 thousands_sep,
581 user_data,
582 internal_context,
583 depth,
584 )
585 }
586 CompiledLogic::Length(expr) => {
587 self.eval_length(expr, user_data, internal_context, depth)
588 }
589 CompiledLogic::Len(expr) => self.eval_len(expr, user_data, internal_context, depth),
590
591 CompiledLogic::Abs(expr) => {
593 self.eval_unary_math(expr, |n| n.abs(), user_data, internal_context, depth)
594 }
595 CompiledLogic::Max(items) => {
596 self.eval_min_max(items, true, user_data, internal_context, depth)
597 }
598 CompiledLogic::Min(items) => {
599 self.eval_min_max(items, false, user_data, internal_context, depth)
600 }
601 CompiledLogic::Pow(base_expr, exp_expr) => {
602 self.eval_pow(base_expr, exp_expr, user_data, internal_context, depth)
603 }
604 CompiledLogic::Round(expr, decimals) => {
605 self.apply_round(expr, decimals, 0, user_data, internal_context, depth)
606 }
607 CompiledLogic::RoundUp(expr, decimals) => {
608 self.apply_round(expr, decimals, 1, user_data, internal_context, depth)
609 }
610 CompiledLogic::RoundDown(expr, decimals) => {
611 self.apply_round(expr, decimals, 2, user_data, internal_context, depth)
612 }
613 CompiledLogic::Ceiling(expr, significance) => {
614 self.eval_ceiling(expr, significance, user_data, internal_context, depth)
615 }
616 CompiledLogic::Floor(expr, significance) => {
617 self.eval_floor(expr, significance, user_data, internal_context, depth)
618 }
619 CompiledLogic::Trunc(expr, decimals) => {
620 self.eval_trunc(expr, decimals, user_data, internal_context, depth)
621 }
622 CompiledLogic::Mround(value_expr, multiple_expr) => self.eval_mround(
623 value_expr,
624 multiple_expr,
625 user_data,
626 internal_context,
627 depth,
628 ),
629
630 CompiledLogic::Today => self.eval_today(),
632 CompiledLogic::Now => self.eval_now(),
633 CompiledLogic::Days(end_expr, start_expr) => {
634 self.eval_days(end_expr, start_expr, user_data, internal_context, depth)
635 }
636 CompiledLogic::Year(expr) => {
637 self.extract_date_component(expr, "year", user_data, internal_context, depth)
638 }
639 CompiledLogic::Month(expr) => {
640 self.extract_date_component(expr, "month", user_data, internal_context, depth)
641 }
642 CompiledLogic::Day(expr) => {
643 self.extract_date_component(expr, "day", user_data, internal_context, depth)
644 }
645 CompiledLogic::Date(year_expr, month_expr, day_expr) => self.eval_date(
646 year_expr,
647 month_expr,
648 day_expr,
649 user_data,
650 internal_context,
651 depth,
652 ),
653 CompiledLogic::DateFormat(date_expr, format_expr) => {
654 self.eval_date_format(date_expr, format_expr, user_data, internal_context, depth)
655 }
656 CompiledLogic::YearFrac(start_expr, end_expr, basis_expr) => self.eval_year_frac(
657 start_expr,
658 end_expr,
659 basis_expr,
660 user_data,
661 internal_context,
662 depth,
663 ),
664 CompiledLogic::DateDif(start_expr, end_expr, unit_expr) => self.eval_date_dif(
665 start_expr,
666 end_expr,
667 unit_expr,
668 user_data,
669 internal_context,
670 depth,
671 ),
672
673 CompiledLogic::Missing(keys) => {
675 let missing: Vec<_> = keys
676 .iter()
677 .filter(|key| self.is_key_missing(user_data, key))
678 .map(|k| Value::String(k.clone()))
679 .collect();
680 Ok(Value::Array(missing))
681 }
682 CompiledLogic::MissingSome(min_expr, keys) => {
683 let min_val =
684 self.evaluate_with_context(min_expr, user_data, internal_context, depth + 1)?;
685 let minimum = to_number(&min_val) as usize;
686
687 let present = keys
688 .iter()
689 .filter(|key| !self.is_key_missing(user_data, key))
690 .count();
691
692 if present >= minimum {
693 Ok(Value::Array(vec![]))
694 } else {
695 let missing: Vec<_> = keys
696 .iter()
697 .filter(|key| self.is_key_missing(user_data, key))
698 .map(|k| Value::String(k.clone()))
699 .collect();
700 Ok(Value::Array(missing))
701 }
702 }
703
704 CompiledLogic::Xor(a_expr, b_expr) => {
706 let a_val =
707 self.evaluate_with_context(a_expr, user_data, internal_context, depth + 1)?;
708 let b_val =
709 self.evaluate_with_context(b_expr, user_data, internal_context, depth + 1)?;
710 Ok(Value::Bool(is_truthy(&a_val) ^ is_truthy(&b_val)))
711 }
712 CompiledLogic::IfNull(cond_expr, alt_expr) => {
713 let cond_val =
714 self.evaluate_with_context(cond_expr, user_data, internal_context, depth + 1)?;
715 if is_null_like(&cond_val) {
716 self.evaluate_with_context(alt_expr, user_data, internal_context, depth + 1)
717 } else {
718 Ok(cond_val)
719 }
720 }
721 CompiledLogic::IsEmpty(expr) => {
722 let val =
723 self.evaluate_with_context(expr, user_data, internal_context, depth + 1)?;
724 let empty = match &val {
725 Value::Null => true,
726 Value::String(s) => s.is_empty(),
727 _ => false,
728 };
729 Ok(Value::Bool(empty))
730 }
731 CompiledLogic::Empty => Ok(Value::String(String::new())),
732
733 CompiledLogic::RangeOptions(min_expr, max_expr) => {
735 let min_val =
736 self.evaluate_with_context(min_expr, user_data, internal_context, depth + 1)?;
737 let max_val =
738 self.evaluate_with_context(max_expr, user_data, internal_context, depth + 1)?;
739
740 let min = to_number(&min_val) as i32;
741 let max = to_number(&max_val) as i32;
742
743 if min > max {
744 return Ok(Value::Array(vec![]));
745 }
746
747 let options: Vec<Value> = (min..=max)
748 .map(|i| {
749 serde_json::json!({
750 "label": i.to_string(),
751 "value": i.to_string()
752 })
753 })
754 .collect();
755
756 Ok(Value::Array(options))
757 }
758 CompiledLogic::MapOptions(table_expr, label_expr, value_expr) => {
759 let table_val =
760 self.evaluate_with_context(table_expr, user_data, internal_context, depth + 1)?;
761 let label_val =
762 self.evaluate_with_context(label_expr, user_data, internal_context, depth + 1)?;
763 let value_val =
764 self.evaluate_with_context(value_expr, user_data, internal_context, depth + 1)?;
765
766 if let (Value::Array(arr), Value::String(label_field), Value::String(value_field)) =
767 (&table_val, &label_val, &value_val)
768 {
769 let options: Vec<Value> = arr
770 .iter()
771 .filter_map(|row| {
772 row.as_object().and_then(|obj| {
773 Some(create_option(obj.get(label_field)?, obj.get(value_field)?))
774 })
775 })
776 .collect();
777 Ok(Value::Array(options))
778 } else {
779 Ok(Value::Array(vec![]))
780 }
781 }
782 CompiledLogic::MapOptionsIf(table_expr, label_expr, value_expr, conditions) => {
783 let table_val =
784 self.evaluate_with_context(table_expr, user_data, internal_context, depth + 1)?;
785 let label_val =
786 self.evaluate_with_context(label_expr, user_data, internal_context, depth + 1)?;
787 let value_val =
788 self.evaluate_with_context(value_expr, user_data, internal_context, depth + 1)?;
789
790 if let (Value::Array(arr), Value::String(label_field), Value::String(value_field)) =
791 (&table_val, &label_val, &value_val)
792 {
793 let mut options = Vec::new();
794
795 for row in arr {
796 let obj = match row.as_object() {
797 Some(obj) => obj,
798 None => continue,
799 };
800
801 let mut all_match = true;
802
803 for condition in conditions {
804 let result =
806 self.evaluate_with_context(condition, row, user_data, depth + 1)?;
807 if !is_truthy(&result) {
808 all_match = false;
809 break;
810 }
811 }
812
813 if all_match {
814 if let (Some(label), Some(value)) =
815 (obj.get(label_field), obj.get(value_field))
816 {
817 options.push(create_option(label, value));
818 }
819 }
820 }
821
822 Ok(Value::Array(options))
823 } else {
824 Ok(Value::Array(vec![]))
825 }
826 }
827 CompiledLogic::Return(value) => {
828 Ok(value.as_ref().clone())
830 }
831 }
832 }
833
834 #[inline]
836 fn eval_var_or_default(
837 &self,
838 name: &str,
839 default: &Option<Box<CompiledLogic>>,
840 user_data: &Value,
841 internal_context: &Value,
842 depth: usize,
843 ) -> Result<Value, String> {
844 if !name.is_empty() {
849 let scope = unsafe { &*self.table_scope.get() };
851 if let Some(ts) = scope.as_ref() {
852 if name == ts.path {
853 let rows = unsafe { &*ts.rows };
855 return Ok(Value::Array(rows.clone()));
856 }
857 }
858 }
859
860 let value = if name.is_empty() {
863 self.get_var(user_data, name)
864 } else {
865 self.get_var(internal_context, name)
866 .or_else(|| self.get_var(user_data, name))
867 };
868 match value {
869 Some(v) if !v.is_null() => Ok(v.clone()), _ => {
871 if let Some(def) = default {
872 self.evaluate_with_context(def, user_data, internal_context, depth + 1)
873 } else {
874 Ok(Value::Null)
875 }
876 }
877 }
878 }
879
880 #[inline(always)]
882 fn f64_to_json(&self, f: f64) -> Value {
883 helpers::f64_to_json(f, self.config.safe_nan_handling)
884 }
885}
886
887impl Default for Evaluator {
888 fn default() -> Self {
889 Self::new()
890 }
891}