json_eval_rs/rlogic/evaluator/
helpers.rs1use serde_json::{Value, Number};
2use crate::path_utils;
3
4#[inline(always)]
6pub fn f64_to_json(f: f64, safe_nan_handling: bool) -> Value {
7 if f.is_finite() {
8 Number::from_f64(f).map(Value::Number).unwrap_or(Value::Null)
9 } else if safe_nan_handling {
10 Value::Number(Number::from_f64(0.0).unwrap())
11 } else {
12 Value::Null
13 }
14}
15
16#[inline(always)]
18pub fn to_f64(value: &Value) -> f64 {
19 match value {
20 Value::Number(n) => n.as_f64().unwrap_or(0.0),
21 Value::Bool(true) => 1.0,
22 Value::Bool(false) => 0.0,
23 Value::String(s) => s.parse::<f64>().unwrap_or(0.0),
24 Value::Array(arr) => {
25 if arr.len() == 1 {
26 to_f64(&arr[0])
27 } else {
28 0.0
29 }
30 }
31 _ => 0.0,
32 }
33}
34
35#[inline]
37pub fn to_number(value: &Value) -> f64 {
38 to_f64(value)
39}
40
41#[inline]
43pub fn parse_string_to_f64(s: &str) -> Option<f64> {
44 if s.is_empty() {
45 Some(0.0)
46 } else {
47 s.parse::<f64>().ok()
48 }
49}
50
51#[inline]
53pub fn to_string(value: &Value) -> String {
54 match value {
55 Value::Null => String::new(),
56 Value::Bool(b) => b.to_string(),
57 Value::Number(n) => {
58 if let Some(f) = n.as_f64() {
61 if f.is_finite() && f == f.floor() && f.abs() < 1e15 {
62 format!("{}", f as i64)
64 } else {
65 n.to_string()
66 }
67 } else {
68 n.to_string()
69 }
70 }
71 Value::String(s) => s.clone(),
72 Value::Array(_) | Value::Object(_) => value.to_string(),
73 }
74}
75
76#[inline]
78pub fn normalize_ref_path(path: &str) -> String {
79 path_utils::normalize_to_json_pointer(path)
80}
81
82#[inline(always)]
85pub fn get_var<'a>(data: &'a Value, name: &str) -> Option<&'a Value> {
86 if name.is_empty() {
87 return Some(data);
88 }
89
90 path_utils::get_value_by_pointer_without_properties(data, name)
93}
94
95#[inline]
97pub fn get_var_layered<'a>(primary: &'a Value, fallback: &'a Value, name: &str) -> Option<&'a Value> {
98 get_var(primary, name).or_else(|| get_var(fallback, name))
99}
100
101#[inline]
103pub fn is_key_missing(data: &Value, key: &str) -> bool {
104 if key.is_empty() {
105 return false;
106 }
107 let pointer = path_utils::normalize_to_json_pointer(key);
108 if pointer.is_empty() {
109 return false;
110 }
111 get_var(data, &pointer).map(|v| v.is_null()).unwrap_or(true)
112}
113
114#[inline]
116pub fn is_truthy(value: &Value) -> bool {
117 match value {
118 Value::Null => false,
119 Value::Bool(b) => *b,
120 Value::Number(n) => n.as_f64().unwrap_or(0.0) != 0.0,
121 Value::String(s) => !s.is_empty(),
122 Value::Array(arr) => !arr.is_empty(),
123 Value::Object(_) => true,
124 }
125}
126
127#[inline]
129pub fn is_null_like(value: &Value) -> bool {
130 match value {
131 Value::Null => true,
132 Value::String(s) if s.is_empty() => true,
133 Value::Number(n) if n.is_f64() && n.as_f64().unwrap().is_nan() => true,
134 _ => false
135 }
136}
137
138#[inline]
140pub fn build_iso_date_string(date: chrono::NaiveDate) -> String {
141 let mut result = String::with_capacity(24);
142 result.push_str(&date.format("%Y-%m-%d").to_string());
143 result.push_str("T00:00:00.000Z");
144 result
145}
146
147#[inline]
149pub fn compare(a: &Value, b: &Value) -> f64 {
150 let num_a = to_f64(a);
151 let num_b = to_f64(b);
152 num_a - num_b
153}
154
155#[inline]
157pub fn create_option(label: &Value, value: &Value) -> Value {
158 serde_json::json!({"label": label, "value": value})
159}
160
161#[inline]
163pub fn scalar_hash_key(value: &Value) -> Option<String> {
164 match value {
165 Value::Null => Some(String::from("null")),
166 Value::Bool(b) => Some(b.to_string()),
167 Value::Number(n) => Some(n.to_string()),
168 Value::String(s) => Some(s.clone()),
169 _ => None,
170 }
171}
172
173pub fn loose_equal(a: &Value, b: &Value) -> bool {
175 match (a, b) {
177 (Value::Null, Value::Null) => true,
179 (Value::Bool(a), Value::Bool(b)) => a == b,
180 (Value::Number(a), Value::Number(b)) => {
181 let a_f64 = a.as_f64().unwrap_or(0.0);
182 let b_f64 = b.as_f64().unwrap_or(0.0);
183 a_f64 == b_f64
184 }
185 (Value::String(a), Value::String(b)) => a == b,
186
187 (Value::Number(n), Value::String(s)) | (Value::String(s), Value::Number(n)) => {
189 let n_val = n.as_f64().unwrap_or(0.0);
190 parse_string_to_f64(s).map(|parsed| n_val == parsed).unwrap_or(false)
191 }
192
193 (Value::Bool(b), Value::Number(n)) | (Value::Number(n), Value::Bool(b)) => {
195 let b_num = if *b { 1.0 } else { 0.0 };
196 b_num == n.as_f64().unwrap_or(0.0)
197 }
198
199 (Value::Bool(b), Value::String(s)) | (Value::String(s), Value::Bool(b)) => {
201 let b_num = if *b { 1.0 } else { 0.0 };
202 parse_string_to_f64(s).map(|parsed| b_num == parsed).unwrap_or(false)
203 }
204
205 (Value::Null, _) | (_, Value::Null) => false,
207
208 _ => a == b,
210 }
211}