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
25const EMPTY_CACHE_SLOT: std::cell::Cell<(usize, u32, u32)> = std::cell::Cell::new((0, 0, 0));
32
33pub(crate) struct TableScope {
34 pub path: String,
36 pub path_no_hash: String,
38 pub rows: *const Vec<Value>,
40 pub flat_cells: *mut Value,
42 pub col_count: usize,
43 pub total_rows: usize,
44 pub existing_row_count: usize,
45 pub col_map: rapidhash::RapidHashMap<String, usize>,
47 pub col_cache: [std::cell::Cell<(usize, u32, u32)>; 256],
49 pub current_row: Option<usize>,
51 pub current_row_base: *mut Value,
53 pub iteration_raw: Option<i64>,
55 pub iteration_val: Option<Value>,
57 pub threshold_val: Option<Value>,
59 pub lookup_cache:
61 std::cell::RefCell<rapidhash::RapidHashMap<types::CombinedLookupKey, Option<usize>>>,
62}
63
64impl TableScope {
65 #[inline(always)]
66 pub fn get_col_idx(&self, col_name: &str) -> Option<usize> {
67 let ptr = col_name.as_ptr() as usize;
68 let len = col_name.len() as u32;
69 let slot = (ptr ^ (ptr >> 6) ^ (len as usize)) & 255;
70 let entry = self.col_cache[slot].get();
71 if entry.0 == ptr && entry.1 == len && ptr != 0 {
72 return Some(entry.2 as usize);
73 }
74 if let Some(&col_idx) = self.col_map.get(col_name) {
75 self.col_cache[slot].set((ptr, len, col_idx as u32));
76 Some(col_idx)
77 } else {
78 None
79 }
80 }
81}
82
83unsafe impl Send for TableScope {}
87unsafe impl Send for Evaluator {}
88unsafe impl Sync for Evaluator {}
89
90pub struct TableScopeGuard<'a> {
92 evaluator: &'a Evaluator,
93}
94
95impl<'a> Drop for TableScopeGuard<'a> {
96 fn drop(&mut self) {
97 unsafe {
99 *self.evaluator.table_scope.get() = None;
100 }
101 }
102}
103
104pub struct Evaluator {
115 config: RLogicConfig,
116 indices: RwLock<HashMap<String, TableIndex>>,
118 static_arrays:
120 UnsafeCell<Option<std::sync::Arc<indexmap::IndexMap<String, std::sync::Arc<Value>>>>>,
121 pub(crate) table_scope: UnsafeCell<Option<TableScope>>,
123}
124
125impl Evaluator {
126 pub fn new() -> Self {
127 Self {
128 config: RLogicConfig::default(),
129 indices: RwLock::new(HashMap::new()),
130 static_arrays: UnsafeCell::new(None),
131 table_scope: UnsafeCell::new(None),
132 }
133 }
134
135 pub(crate) fn enter_table_scope<'a>(
143 &'a self,
144 path: String,
145 rows: &Vec<Value>,
146 ) -> TableScopeGuard<'a> {
147 let path_no_hash = path.trim_start_matches('#').to_string();
148 unsafe {
150 *self.table_scope.get() = Some(TableScope {
151 path,
152 path_no_hash,
153 rows: rows as *const Vec<Value>,
154 flat_cells: std::ptr::null_mut(),
155 col_count: 0,
156 total_rows: 0,
157 existing_row_count: 0,
158 col_map: rapidhash::RapidHashMap::default(),
159 col_cache: [EMPTY_CACHE_SLOT; 256],
160 current_row: None,
161 current_row_base: std::ptr::null_mut(),
162 iteration_raw: None,
163 iteration_val: None,
164 threshold_val: None,
165 lookup_cache: std::cell::RefCell::new(rapidhash::RapidHashMap::default()),
166 });
167 }
168 TableScopeGuard { evaluator: self }
169 }
170
171 pub(crate) fn set_table_scope_flat_cells(
173 &self,
174 cells: *mut Value,
175 col_count: usize,
176 total_rows: usize,
177 existing_row_count: usize,
178 col_map: rapidhash::RapidHashMap<String, usize>,
179 ) {
180 unsafe {
182 if let Some(ts) = (*self.table_scope.get()).as_mut() {
183 ts.flat_cells = cells;
184 ts.col_count = col_count;
185 ts.total_rows = total_rows;
186 ts.existing_row_count = existing_row_count;
187 ts.col_map = col_map;
188 ts.col_cache = [EMPTY_CACHE_SLOT; 256];
189 ts.current_row_base = std::ptr::null_mut();
190 }
191 }
192 }
193
194 pub(crate) fn update_table_scope_rows(&self, rows: &Vec<Value>) {
196 unsafe {
198 if let Some(ts) = (*self.table_scope.get()).as_mut() {
199 ts.rows = rows as *const Vec<Value>;
200 }
201 }
202 }
203
204 pub(crate) fn set_table_scope_row(&self, row_idx: Option<usize>) {
206 unsafe {
208 if let Some(ts) = (*self.table_scope.get()).as_mut() {
209 ts.current_row = row_idx;
210 if let Some(r) = row_idx {
211 if ts.col_count > 0
212 && !ts.flat_cells.is_null()
213 && r >= ts.existing_row_count
214 && r < ts.existing_row_count + ts.total_rows
215 {
216 ts.current_row_base = ts
217 .flat_cells
218 .add((r - ts.existing_row_count) * ts.col_count);
219 } else {
220 ts.current_row_base = std::ptr::null_mut();
221 }
222 } else {
223 ts.current_row_base = std::ptr::null_mut();
224 }
225 }
226 }
227 }
228
229 pub(crate) fn set_table_scope_cursor(&self, row_idx: Option<usize>, iteration: Option<i64>) {
231 unsafe {
233 if let Some(ts) = (*self.table_scope.get()).as_mut() {
234 ts.current_row = row_idx;
235 ts.iteration_raw = iteration;
236 ts.iteration_val = iteration.map(Value::from);
237 if let Some(r) = row_idx {
238 if ts.col_count > 0
239 && !ts.flat_cells.is_null()
240 && r >= ts.existing_row_count
241 && r < ts.existing_row_count + ts.total_rows
242 {
243 ts.current_row_base = ts
244 .flat_cells
245 .add((r - ts.existing_row_count) * ts.col_count);
246 } else {
247 ts.current_row_base = std::ptr::null_mut();
248 }
249 } else {
250 ts.current_row_base = std::ptr::null_mut();
251 }
252 }
253 }
254 }
255
256 pub(crate) fn set_table_scope_threshold(&self, threshold: i64) {
258 unsafe {
260 if let Some(ts) = (*self.table_scope.get()).as_mut() {
261 ts.threshold_val = Some(Value::from(threshold));
262 }
263 }
264 }
265
266 pub fn with_config(mut self, config: RLogicConfig) -> Self {
267 self.config = config;
268 self
269 }
270
271 pub fn set_static_arrays(
273 &self,
274 static_arrays: std::sync::Arc<indexmap::IndexMap<String, std::sync::Arc<Value>>>,
275 ) {
276 unsafe {
278 *self.static_arrays.get() = Some(static_arrays);
279 }
280 }
281
282 pub fn index_table(&self, name: &str, data: &Value) {
284 if let Some(index) = TableIndex::new(data) {
285 if let Ok(mut indices) = self.indices.write() {
286 indices.insert(name.to_string(), index);
287 }
288 }
289 }
290
291 pub fn clear_indices(&self) {
293 if let Ok(mut indices) = self.indices.write() {
294 indices.clear();
295 }
296 }
297
298 #[inline]
301 pub fn evaluate(&self, logic: &CompiledLogic, data: &Value) -> Result<Value, String> {
302 match logic {
304 CompiledLogic::Null => return Ok(Value::Null),
305 CompiledLogic::Bool(b) => return Ok(Value::Bool(*b)),
306 CompiledLogic::Number(n) => {
307 return Ok(self.f64_to_json(*n));
308 }
309 CompiledLogic::String(s) => return Ok(Value::String(s.clone())),
310 CompiledLogic::Var(name, None) if !name.is_empty() => {
311 return self.eval_var_or_default(name, &None, data, &Value::Null, 0);
313 }
314 CompiledLogic::Ref(path, None) if !path.is_empty() => {
315 return self.eval_var_or_default(path, &None, data, &Value::Null, 0);
317 }
318 CompiledLogic::Add(_)
320 | CompiledLogic::Subtract(_)
321 | CompiledLogic::Multiply(_)
322 | CompiledLogic::Divide(_) => {
323 if let Some(result) = self.eval_f64(logic, data, &Value::Null, 0)? {
324 return Ok(self.f64_to_json(result));
325 }
326 }
327 _ => {}
328 }
329
330 self.evaluate_with_context(logic, data, &Value::Null, 0)
332 }
333
334 #[inline]
345 pub fn evaluate_with_internal_context(
346 &self,
347 logic: &CompiledLogic,
348 user_data: &Value,
349 internal_context: &Value,
350 ) -> Result<Value, String> {
351 self.evaluate_with_context(logic, user_data, internal_context, 0)
352 }
353
354 fn evaluate_with_context(
362 &self,
363 logic: &CompiledLogic,
364 user_data: &Value,
365 internal_context: &Value,
366 depth: usize,
367 ) -> Result<Value, String> {
368 if depth > self.config.recursion_limit {
370 return Err("Recursion limit exceeded".to_string());
371 }
372
373 match logic {
374 CompiledLogic::Null => Ok(Value::Null),
376 CompiledLogic::Bool(b) => Ok(Value::Bool(*b)),
377 CompiledLogic::Number(n) => Ok(self.f64_to_json(*n)),
378 CompiledLogic::String(s) => Ok(Value::String(s.clone())),
379 CompiledLogic::Array(arr) => {
380 let results: Result<Vec<_>, _> = arr
381 .iter()
382 .map(|item| {
383 self.evaluate_with_context(item, user_data, internal_context, depth + 1)
384 })
385 .collect();
386 Ok(Value::Array(results?))
387 }
388
389 CompiledLogic::Var(name, default) => {
391 self.eval_var_or_default(name, default, user_data, internal_context, depth)
392 }
393
394 CompiledLogic::Ref(path, default) => {
395 self.eval_var_or_default(path, default, user_data, internal_context, depth)
396 }
397
398 CompiledLogic::And(items) => {
400 self.eval_and_or(items, true, user_data, internal_context, depth)
401 }
402 CompiledLogic::Or(items) => {
403 self.eval_and_or(items, false, user_data, internal_context, depth)
404 }
405 CompiledLogic::Not(expr) => {
406 let result =
407 self.evaluate_with_context(expr, user_data, internal_context, depth + 1)?;
408 Ok(Value::Bool(!is_truthy(&result)))
409 }
410 CompiledLogic::If(cond, then_expr, else_expr) => {
411 if self.eval_truthy(cond, user_data, internal_context, depth + 1)? {
412 self.evaluate_with_context(then_expr, user_data, internal_context, depth + 1)
413 } else {
414 self.evaluate_with_context(else_expr, user_data, internal_context, depth + 1)
415 }
416 }
417
418 CompiledLogic::Equal(a, b) => {
420 self.eval_binary_compare(CompOp::Eq, a, b, user_data, internal_context, depth)
421 }
422 CompiledLogic::StrictEqual(a, b) => {
423 self.eval_binary_compare(CompOp::StrictEq, a, b, user_data, internal_context, depth)
424 }
425 CompiledLogic::NotEqual(a, b) => {
426 self.eval_binary_compare(CompOp::Ne, a, b, user_data, internal_context, depth)
427 }
428 CompiledLogic::StrictNotEqual(a, b) => {
429 self.eval_binary_compare(CompOp::StrictNe, a, b, user_data, internal_context, depth)
430 }
431 CompiledLogic::LessThan(a, b) => {
432 self.eval_binary_compare(CompOp::Lt, a, b, user_data, internal_context, depth)
433 }
434 CompiledLogic::LessThanOrEqual(a, b) => {
435 self.eval_binary_compare(CompOp::Le, a, b, user_data, internal_context, depth)
436 }
437 CompiledLogic::GreaterThan(a, b) => {
438 self.eval_binary_compare(CompOp::Gt, a, b, user_data, internal_context, depth)
439 }
440 CompiledLogic::GreaterThanOrEqual(a, b) => {
441 self.eval_binary_compare(CompOp::Ge, a, b, user_data, internal_context, depth)
442 }
443
444 CompiledLogic::Add(_)
446 | CompiledLogic::Subtract(_)
447 | CompiledLogic::Multiply(_)
448 | CompiledLogic::Divide(_)
449 | CompiledLogic::Power(_, _)
450 | CompiledLogic::Modulo(_, _) => {
451 match self.eval_f64(logic, user_data, internal_context, depth)? {
452 Some(result) => Ok(self.f64_to_json(result)),
453 None => Ok(Value::Null),
454 }
455 }
456
457 CompiledLogic::Map(array_expr, logic_expr) => {
459 self.eval_map(array_expr, logic_expr, user_data, internal_context, depth)
460 }
461 CompiledLogic::Filter(array_expr, logic_expr) => {
462 self.eval_filter(array_expr, logic_expr, user_data, internal_context, depth)
463 }
464 CompiledLogic::Reduce(array_expr, logic_expr, initial_expr) => self.eval_reduce(
465 array_expr,
466 logic_expr,
467 initial_expr,
468 user_data,
469 internal_context,
470 depth,
471 ),
472 CompiledLogic::All(array_expr, logic_expr) => self.eval_quantifier(
473 Quantifier::All,
474 array_expr,
475 logic_expr,
476 user_data,
477 internal_context,
478 depth,
479 ),
480 CompiledLogic::Some(array_expr, logic_expr) => self.eval_quantifier(
481 Quantifier::Some,
482 array_expr,
483 logic_expr,
484 user_data,
485 internal_context,
486 depth,
487 ),
488 CompiledLogic::None(array_expr, logic_expr) => self.eval_quantifier(
489 Quantifier::None,
490 array_expr,
491 logic_expr,
492 user_data,
493 internal_context,
494 depth,
495 ),
496 CompiledLogic::Merge(items) => {
497 self.eval_merge(items, user_data, internal_context, depth)
498 }
499 CompiledLogic::In(value_expr, array_expr) => {
500 self.eval_in(value_expr, array_expr, user_data, internal_context, depth)
501 }
502 CompiledLogic::Sum(array_expr, field_expr, threshold_expr) => self.eval_sum(
503 array_expr,
504 field_expr,
505 threshold_expr,
506 user_data,
507 internal_context,
508 depth,
509 ),
510 CompiledLogic::For(start_expr, end_expr, logic_expr) => self.eval_for(
511 start_expr,
512 end_expr,
513 logic_expr,
514 user_data,
515 internal_context,
516 depth,
517 ),
518 CompiledLogic::Multiplies(items) => {
519 self.eval_multiplies(items, user_data, internal_context, depth)
520 }
521 CompiledLogic::Divides(items) => {
522 self.eval_divides(items, user_data, internal_context, depth)
523 }
524
525 CompiledLogic::ValueAt(table_expr, row_idx_expr, col_name_expr) => self.eval_valueat(
527 table_expr,
528 row_idx_expr,
529 col_name_expr,
530 user_data,
531 internal_context,
532 depth,
533 ),
534 CompiledLogic::MaxAt(table_expr, col_name_expr) => self.eval_maxat(
535 table_expr,
536 col_name_expr,
537 user_data,
538 internal_context,
539 depth,
540 ),
541 CompiledLogic::IndexAt(lookup_expr, table_expr, field_expr, range_expr) => self
542 .eval_indexat(
543 lookup_expr,
544 table_expr,
545 field_expr,
546 range_expr,
547 user_data,
548 internal_context,
549 depth,
550 ),
551 CompiledLogic::Match(table_expr, conditions) => {
552 self.eval_match(table_expr, conditions, user_data, internal_context, depth)
553 }
554 CompiledLogic::MatchRange(table_expr, conditions) => {
555 self.eval_matchrange(table_expr, conditions, user_data, internal_context, depth)
556 }
557 CompiledLogic::Choose(table_expr, conditions) => {
558 self.eval_choose(table_expr, conditions, user_data, internal_context, depth)
559 }
560 CompiledLogic::FindIndex(table_expr, conditions) => {
561 self.eval_findindex(table_expr, conditions, user_data, internal_context, depth)
562 }
563
564 CompiledLogic::Cat(items) => {
566 self.concat_strings(items, user_data, internal_context, depth)
567 }
568 CompiledLogic::Substr(string_expr, start_expr, length_expr) => self.eval_substr(
569 string_expr,
570 start_expr,
571 length_expr,
572 user_data,
573 internal_context,
574 depth,
575 ),
576 CompiledLogic::Search(find_expr, within_expr, start_expr) => self.eval_search(
577 find_expr,
578 within_expr,
579 start_expr,
580 user_data,
581 internal_context,
582 depth,
583 ),
584 CompiledLogic::Left(text_expr, num_expr) => self.extract_text_side(
585 text_expr,
586 num_expr.as_deref(),
587 true,
588 user_data,
589 internal_context,
590 depth,
591 ),
592 CompiledLogic::Right(text_expr, num_expr) => self.extract_text_side(
593 text_expr,
594 num_expr.as_deref(),
595 false,
596 user_data,
597 internal_context,
598 depth,
599 ),
600 CompiledLogic::Mid(text_expr, start_expr, num_expr) => self.eval_mid(
601 text_expr,
602 start_expr,
603 num_expr,
604 user_data,
605 internal_context,
606 depth,
607 ),
608 CompiledLogic::SplitText(value_expr, sep_expr, index_expr) => self.eval_split_text(
609 value_expr,
610 sep_expr,
611 index_expr,
612 user_data,
613 internal_context,
614 depth,
615 ),
616 CompiledLogic::Concat(items) => {
617 self.concat_strings(items, user_data, internal_context, depth)
618 }
619 CompiledLogic::SplitValue(string_expr, sep_expr) => {
620 self.eval_split_value(string_expr, sep_expr, user_data, internal_context, depth)
621 }
622 CompiledLogic::StringFormat(value_expr, decimals, prefix, suffix, thousands_sep) => {
623 self.eval_string_format(
624 value_expr,
625 decimals,
626 prefix,
627 suffix,
628 thousands_sep,
629 user_data,
630 internal_context,
631 depth,
632 )
633 }
634 CompiledLogic::Length(expr) => {
635 self.eval_length(expr, user_data, internal_context, depth)
636 }
637 CompiledLogic::Len(expr) => self.eval_len(expr, user_data, internal_context, depth),
638
639 CompiledLogic::Abs(expr) => {
641 self.eval_unary_math(expr, |n| n.abs(), user_data, internal_context, depth)
642 }
643 CompiledLogic::Max(items) => {
644 self.eval_min_max(items, true, user_data, internal_context, depth)
645 }
646 CompiledLogic::Min(items) => {
647 self.eval_min_max(items, false, user_data, internal_context, depth)
648 }
649 CompiledLogic::Pow(base_expr, exp_expr) => {
650 self.eval_pow(base_expr, exp_expr, user_data, internal_context, depth)
651 }
652 CompiledLogic::Round(expr, decimals) => {
653 self.apply_round(expr, decimals, 0, user_data, internal_context, depth)
654 }
655 CompiledLogic::RoundUp(expr, decimals) => {
656 self.apply_round(expr, decimals, 1, user_data, internal_context, depth)
657 }
658 CompiledLogic::RoundDown(expr, decimals) => {
659 self.apply_round(expr, decimals, 2, user_data, internal_context, depth)
660 }
661 CompiledLogic::Ceiling(expr, significance) => {
662 self.eval_ceiling(expr, significance, user_data, internal_context, depth)
663 }
664 CompiledLogic::Floor(expr, significance) => {
665 self.eval_floor(expr, significance, user_data, internal_context, depth)
666 }
667 CompiledLogic::Trunc(expr, decimals) => {
668 self.eval_trunc(expr, decimals, user_data, internal_context, depth)
669 }
670 CompiledLogic::Mround(value_expr, multiple_expr) => self.eval_mround(
671 value_expr,
672 multiple_expr,
673 user_data,
674 internal_context,
675 depth,
676 ),
677
678 CompiledLogic::Today => self.eval_today(),
680 CompiledLogic::Now => self.eval_now(),
681 CompiledLogic::Days(end_expr, start_expr) => {
682 self.eval_days(end_expr, start_expr, user_data, internal_context, depth)
683 }
684 CompiledLogic::Year(expr) => {
685 self.extract_date_component(expr, "year", user_data, internal_context, depth)
686 }
687 CompiledLogic::Month(expr) => {
688 self.extract_date_component(expr, "month", user_data, internal_context, depth)
689 }
690 CompiledLogic::Day(expr) => {
691 self.extract_date_component(expr, "day", user_data, internal_context, depth)
692 }
693 CompiledLogic::Date(year_expr, month_expr, day_expr) => self.eval_date(
694 year_expr,
695 month_expr,
696 day_expr,
697 user_data,
698 internal_context,
699 depth,
700 ),
701 CompiledLogic::DateFormat(date_expr, format_expr) => {
702 self.eval_date_format(date_expr, format_expr, user_data, internal_context, depth)
703 }
704 CompiledLogic::YearFrac(start_expr, end_expr, basis_expr) => self.eval_year_frac(
705 start_expr,
706 end_expr,
707 basis_expr,
708 user_data,
709 internal_context,
710 depth,
711 ),
712 CompiledLogic::DateDif(start_expr, end_expr, unit_expr) => self.eval_date_dif(
713 start_expr,
714 end_expr,
715 unit_expr,
716 user_data,
717 internal_context,
718 depth,
719 ),
720
721 CompiledLogic::Missing(keys) => {
723 let missing: Vec<_> = keys
724 .iter()
725 .filter(|key| self.is_key_missing(user_data, key))
726 .map(|k| Value::String(k.clone()))
727 .collect();
728 Ok(Value::Array(missing))
729 }
730 CompiledLogic::MissingSome(min_expr, keys) => {
731 let min_val =
732 self.evaluate_with_context(min_expr, user_data, internal_context, depth + 1)?;
733 let minimum = to_number(&min_val) as usize;
734
735 let present = keys
736 .iter()
737 .filter(|key| !self.is_key_missing(user_data, key))
738 .count();
739
740 if present >= minimum {
741 Ok(Value::Array(vec![]))
742 } else {
743 let missing: Vec<_> = keys
744 .iter()
745 .filter(|key| self.is_key_missing(user_data, key))
746 .map(|k| Value::String(k.clone()))
747 .collect();
748 Ok(Value::Array(missing))
749 }
750 }
751
752 CompiledLogic::Xor(a_expr, b_expr) => {
754 let a_val =
755 self.evaluate_with_context(a_expr, user_data, internal_context, depth + 1)?;
756 let b_val =
757 self.evaluate_with_context(b_expr, user_data, internal_context, depth + 1)?;
758 Ok(Value::Bool(is_truthy(&a_val) ^ is_truthy(&b_val)))
759 }
760 CompiledLogic::IfNull(cond_expr, alt_expr) => {
761 let cond_val =
762 self.evaluate_with_context(cond_expr, user_data, internal_context, depth + 1)?;
763 if is_null_like(&cond_val) {
764 self.evaluate_with_context(alt_expr, user_data, internal_context, depth + 1)
765 } else {
766 Ok(cond_val)
767 }
768 }
769 CompiledLogic::IsEmpty(expr) => {
770 let val =
771 self.evaluate_with_context(expr, user_data, internal_context, depth + 1)?;
772 let empty = match &val {
773 Value::Null => true,
774 Value::String(s) => s.is_empty(),
775 _ => false,
776 };
777 Ok(Value::Bool(empty))
778 }
779 CompiledLogic::Empty => Ok(Value::String(String::new())),
780
781 CompiledLogic::RangeOptions(min_expr, max_expr) => {
783 let min_val =
784 self.evaluate_with_context(min_expr, user_data, internal_context, depth + 1)?;
785 let max_val =
786 self.evaluate_with_context(max_expr, user_data, internal_context, depth + 1)?;
787
788 let min = to_number(&min_val) as i32;
789 let max = to_number(&max_val) as i32;
790
791 if min > max {
792 return Ok(Value::Array(vec![]));
793 }
794
795 let options: Vec<Value> = (min..=max)
796 .map(|i| {
797 serde_json::json!({
798 "label": i.to_string(),
799 "value": i.to_string()
800 })
801 })
802 .collect();
803
804 Ok(Value::Array(options))
805 }
806 CompiledLogic::MapOptions(table_expr, label_expr, value_expr) => {
807 let table_val =
808 self.evaluate_with_context(table_expr, user_data, internal_context, depth + 1)?;
809 let label_val =
810 self.evaluate_with_context(label_expr, user_data, internal_context, depth + 1)?;
811 let value_val =
812 self.evaluate_with_context(value_expr, user_data, internal_context, depth + 1)?;
813
814 if let (Value::Array(arr), Value::String(label_field), Value::String(value_field)) =
815 (&table_val, &label_val, &value_val)
816 {
817 let options: Vec<Value> = arr
818 .iter()
819 .filter_map(|row| {
820 row.as_object().and_then(|obj| {
821 Some(create_option(obj.get(label_field)?, obj.get(value_field)?))
822 })
823 })
824 .collect();
825 Ok(Value::Array(options))
826 } else {
827 Ok(Value::Array(vec![]))
828 }
829 }
830 CompiledLogic::MapOptionsIf(table_expr, label_expr, value_expr, conditions) => {
831 let table_val =
832 self.evaluate_with_context(table_expr, user_data, internal_context, depth + 1)?;
833 let label_val =
834 self.evaluate_with_context(label_expr, user_data, internal_context, depth + 1)?;
835 let value_val =
836 self.evaluate_with_context(value_expr, user_data, internal_context, depth + 1)?;
837
838 if let (Value::Array(arr), Value::String(label_field), Value::String(value_field)) =
839 (&table_val, &label_val, &value_val)
840 {
841 let mut options = Vec::new();
842
843 for row in arr {
844 let obj = match row.as_object() {
845 Some(obj) => obj,
846 None => continue,
847 };
848
849 let mut all_match = true;
850
851 for condition in conditions {
852 let result =
854 self.evaluate_with_context(condition, row, user_data, depth + 1)?;
855 if !is_truthy(&result) {
856 all_match = false;
857 break;
858 }
859 }
860
861 if all_match {
862 if let (Some(label), Some(value)) =
863 (obj.get(label_field), obj.get(value_field))
864 {
865 options.push(create_option(label, value));
866 }
867 }
868 }
869
870 Ok(Value::Array(options))
871 } else {
872 Ok(Value::Array(vec![]))
873 }
874 }
875 CompiledLogic::Return(value) => {
876 Ok(value.as_ref().clone())
878 }
879 }
880 }
881
882 #[inline]
884 fn eval_var_or_default(
885 &self,
886 name: &str,
887 default: &Option<Box<CompiledLogic>>,
888 user_data: &Value,
889 internal_context: &Value,
890 depth: usize,
891 ) -> Result<Value, String> {
892 if !name.is_empty() {
897 let scope = unsafe { &*self.table_scope.get() };
899 if let Some(ts) = scope.as_ref() {
900 if name == ts.path || name.trim_start_matches('#') == ts.path_no_hash.as_str() {
901 if ts.col_count > 0 && !ts.flat_cells.is_null() {
902 let mut arr = Vec::with_capacity(ts.existing_row_count + ts.total_rows);
903 let rows = unsafe { &*ts.rows };
904 for r in 0..ts.existing_row_count {
905 if let Some(row) = rows.get(r) {
906 arr.push(row.clone());
907 }
908 }
909 for r in 0..ts.total_rows {
910 let mut row_map = serde_json::Map::with_capacity(ts.col_count);
911 let row_offset = r * ts.col_count;
912 for (c_name, &c_idx) in ts.col_map.iter() {
913 let cell = unsafe { &*ts.flat_cells.add(row_offset + c_idx) };
914 row_map.insert(c_name.clone(), cell.clone());
915 }
916 arr.push(Value::Object(row_map));
917 }
918 return Ok(Value::Array(arr));
919 }
920 let rows = unsafe { &*ts.rows };
922 return Ok(Value::Array(rows.clone()));
923 }
924 }
925 }
926
927 let value = if name.is_empty() {
930 self.get_var(user_data, name)
931 } else {
932 self.get_var(internal_context, name)
933 .or_else(|| self.get_var(user_data, name))
934 };
935 match value {
936 Some(v) if !v.is_null() => Ok(v.clone()), _ => {
938 if let Some(def) = default {
939 self.evaluate_with_context(def, user_data, internal_context, depth + 1)
940 } else {
941 Ok(Value::Null)
942 }
943 }
944 }
945 }
946
947 #[inline(always)]
949 pub fn f64_to_value(&self, f: f64) -> Value {
950 helpers::f64_to_json(f, self.config.safe_nan_handling)
951 }
952
953 #[inline(always)]
954 fn f64_to_json(&self, f: f64) -> Value {
955 self.f64_to_value(f)
956 }
957
958 #[inline(always)]
959 pub fn eval_fast_f64(
960 &self,
961 logic: &CompiledLogic,
962 user_data: &Value,
963 internal_context: &Value,
964 ) -> Result<Option<f64>, String> {
965 self.eval_f64(logic, user_data, internal_context, 0)
966 }
967}
968
969impl Default for Evaluator {
970 fn default() -> Self {
971 Self::new()
972 }
973}