datalogic_rs/config.rs
1//! Configuration module for customizable DataLogic behavior
2//!
3//! This module provides configuration options to customize the evaluation behavior
4//! of the DataLogic engine while maintaining backward compatibility.
5
6use serde_json::Value;
7use std::sync::Arc;
8
9/// Main configuration structure for DataLogic evaluation behavior
10#[derive(Clone)]
11pub struct EvaluationConfig {
12 /// How to handle NaN (Not a Number) in arithmetic operations
13 pub arithmetic_nan_handling: NanHandling,
14
15 /// How to handle division by zero
16 pub division_by_zero: DivisionByZeroHandling,
17
18 /// Whether to throw errors for incompatible types in loose equality
19 pub loose_equality_errors: bool,
20
21 /// How to evaluate truthiness of values
22 pub truthy_evaluator: TruthyEvaluator,
23
24 /// Configuration for numeric coercion behavior
25 pub numeric_coercion: NumericCoercionConfig,
26}
27
28/// Defines how to handle NaN (Not a Number) scenarios in arithmetic operations
29#[derive(Clone, Debug, PartialEq)]
30pub enum NanHandling {
31 /// Throw an error when encountering non-numeric values (default)
32 ThrowError,
33 /// Ignore non-numeric values and continue with remaining values
34 IgnoreValue,
35 /// Treat non-numeric values as zero
36 CoerceToZero,
37 /// Return null when encountering non-numeric values
38 ReturnNull,
39}
40
41/// Defines how to handle division by zero
42#[derive(Clone, Debug, PartialEq)]
43pub enum DivisionByZeroHandling {
44 /// Return f64::MAX or f64::MIN based on sign (default)
45 ReturnBounds,
46 /// Throw an error
47 ThrowError,
48 /// Return null
49 ReturnNull,
50 /// Return infinity (positive or negative based on dividend sign)
51 ReturnInfinity,
52}
53
54/// Defines how to evaluate truthiness of values
55#[derive(Clone)]
56pub enum TruthyEvaluator {
57 /// JavaScript-style truthiness (default)
58 /// - false: null, false, 0, NaN, "", empty array, empty object
59 /// - true: everything else
60 JavaScript,
61
62 /// Python-style truthiness
63 /// - false: None/null, False, 0, 0.0, "", empty collections
64 /// - true: everything else
65 Python,
66
67 /// Strict boolean truthiness
68 /// - false: null, false
69 /// - true: everything else
70 StrictBoolean,
71
72 /// Custom truthiness evaluator
73 Custom(Arc<dyn Fn(&Value) -> bool + Send + Sync>),
74}
75
76/// Configuration for numeric coercion behavior
77#[derive(Clone, Debug)]
78pub struct NumericCoercionConfig {
79 /// Convert empty strings to 0 (default: true)
80 pub empty_string_to_zero: bool,
81
82 /// Convert null to 0 (default: true)
83 pub null_to_zero: bool,
84
85 /// Convert booleans to numbers (true=1, false=0) (default: true)
86 pub bool_to_number: bool,
87
88 /// Only allow strict numeric parsing (no coercion) (default: false)
89 pub strict_numeric: bool,
90
91 /// Convert undefined/missing values to 0 (default: false)
92 pub undefined_to_zero: bool,
93}
94
95impl Default for EvaluationConfig {
96 fn default() -> Self {
97 Self {
98 arithmetic_nan_handling: NanHandling::ThrowError,
99 division_by_zero: DivisionByZeroHandling::ReturnBounds,
100 loose_equality_errors: true,
101 truthy_evaluator: TruthyEvaluator::JavaScript,
102 numeric_coercion: NumericCoercionConfig::default(),
103 }
104 }
105}
106
107impl Default for NumericCoercionConfig {
108 fn default() -> Self {
109 Self {
110 empty_string_to_zero: true,
111 null_to_zero: true,
112 bool_to_number: true,
113 strict_numeric: false,
114 undefined_to_zero: false,
115 }
116 }
117}
118
119impl EvaluationConfig {
120 /// Create a new configuration with default settings
121 pub fn new() -> Self {
122 Self::default()
123 }
124
125 /// Create a configuration with safe arithmetic (ignores non-numeric values)
126 pub fn safe_arithmetic() -> Self {
127 Self {
128 arithmetic_nan_handling: NanHandling::IgnoreValue,
129 division_by_zero: DivisionByZeroHandling::ReturnNull,
130 loose_equality_errors: false,
131 ..Default::default()
132 }
133 }
134
135 /// Create a configuration with strict behavior (more errors)
136 pub fn strict() -> Self {
137 Self {
138 arithmetic_nan_handling: NanHandling::ThrowError,
139 division_by_zero: DivisionByZeroHandling::ThrowError,
140 loose_equality_errors: true,
141 numeric_coercion: NumericCoercionConfig {
142 empty_string_to_zero: false,
143 null_to_zero: false,
144 bool_to_number: false,
145 strict_numeric: true,
146 undefined_to_zero: false,
147 },
148 ..Default::default()
149 }
150 }
151
152 /// Builder method to set NaN handling
153 pub fn with_nan_handling(mut self, handling: NanHandling) -> Self {
154 self.arithmetic_nan_handling = handling;
155 self
156 }
157
158 /// Builder method to set division by zero handling
159 pub fn with_division_by_zero(mut self, handling: DivisionByZeroHandling) -> Self {
160 self.division_by_zero = handling;
161 self
162 }
163
164 /// Builder method to set loose equality error behavior
165 pub fn with_loose_equality_errors(mut self, throw_errors: bool) -> Self {
166 self.loose_equality_errors = throw_errors;
167 self
168 }
169
170 /// Builder method to set truthy evaluator
171 pub fn with_truthy_evaluator(mut self, evaluator: TruthyEvaluator) -> Self {
172 self.truthy_evaluator = evaluator;
173 self
174 }
175
176 /// Builder method to set numeric coercion config
177 pub fn with_numeric_coercion(mut self, config: NumericCoercionConfig) -> Self {
178 self.numeric_coercion = config;
179 self
180 }
181}