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