1use serde::{Deserialize, Deserializer, Serialize, Serializer};
2use serde_json::{json, Map as JsonMap, Number as JsonNumber, Value as JsonValue};
3use std::{collections::HashMap, fmt::Debug};
4
5use crate::{
6 hashing::{self, ahash_str},
7 log_w,
8 value_parsing::{maybe_parse_f64, maybe_parse_i64, try_parse_timestamp},
9};
10
11use super::dynamic_string::DynamicString;
12
13const TAG: &str = "DynamicValue";
14
15#[macro_export]
16macro_rules! dyn_value {
17 ($x:expr) => {{
18 $crate::DynamicValue::from_json_value($x)
19 }};
20}
21
22#[derive(Debug, Clone, Default)]
23pub struct DynamicValue {
24 pub null: Option<()>,
25 pub bool_value: Option<bool>,
26 pub int_value: Option<i64>,
27 pub float_value: Option<f64>,
28 pub timestamp_value: Option<i64>,
29 pub string_value: Option<DynamicString>,
30 pub array_value: Option<Vec<DynamicValue>>,
31 pub object_value: Option<HashMap<String, DynamicValue>>,
32 pub json_value: JsonValue,
33 pub hash_value: u64,
34}
35
36impl DynamicValue {
37 #[must_use]
38 pub fn new() -> Self {
39 Self::default()
40 }
41
42 #[must_use]
43 pub fn from_json_value(value: impl Serialize) -> Self {
44 Self::from(json!(value))
45 }
46
47 #[must_use]
48 pub fn for_timestamp_evaluation(timestamp: i64) -> DynamicValue {
49 DynamicValue {
50 int_value: Some(timestamp),
51 ..DynamicValue::default()
52 }
53 }
54
55 #[must_use]
56 pub fn from_string(value: impl Into<String>) -> Self {
57 let value = value.into();
58 let int_value = maybe_parse_i64(&value);
59 let float_value = maybe_parse_f64(&value);
60 let timestamp_value = try_parse_timestamp(&value, int_value);
61 let hash_value = ahash_str(&value);
62
63 DynamicValue {
64 string_value: Some(DynamicString::from(value.clone())),
65 json_value: JsonValue::String(value),
66 timestamp_value,
67 int_value,
68 float_value,
69 hash_value,
70 ..DynamicValue::new()
71 }
72 }
73
74 #[must_use]
75 pub fn from_bool(value: bool) -> Self {
76 let string_value = if value { "true" } else { "false" };
77
78 DynamicValue {
79 bool_value: Some(value),
80 string_value: Some(DynamicString::from_bool(value)),
81 json_value: JsonValue::Bool(value),
82 hash_value: ahash_str(string_value),
83 ..DynamicValue::new()
84 }
85 }
86
87 #[must_use]
88 pub fn from_i64(value: i64) -> Self {
89 let string_value = value.to_string();
90
91 DynamicValue {
92 int_value: Some(value),
93 float_value: Some(value as f64),
94 string_value: Some(DynamicString::from(string_value.clone())),
95 json_value: JsonValue::Number(JsonNumber::from(value)),
96 hash_value: ahash_str(&string_value),
97 ..DynamicValue::new()
98 }
99 }
100
101 #[must_use]
102 pub fn from_f64(value: f64) -> Self {
103 let num = match JsonNumber::from_f64(value) {
104 Some(num) => num,
105 None => {
106 log_w!(
107 TAG,
108 "Failed to convert f64 to serde_json::Number: {}",
109 value
110 );
111 return Self::from_i64(value as i64);
112 }
113 };
114
115 let json_string = JsonValue::Number(num.clone()).to_string();
116 let mut float_value = num.as_f64();
117 let mut int_value = num.as_i64();
118 if let (Some(f), None) = (float_value, int_value) {
119 let iv = f as i64;
120 if iv as f64 == f {
121 int_value = Some(iv);
122 }
123 } else if let (None, Some(i)) = (float_value, int_value) {
124 let fv = i as f64;
125 if fv as i64 == i {
126 float_value = Some(fv)
127 }
128 }
129
130 let string_value = float_value
131 .map(|f| f.to_string())
132 .or_else(|| int_value.map(|i| i.to_string()))
133 .unwrap_or_else(|| json_string.clone());
134
135 DynamicValue {
136 float_value,
137 int_value,
138 string_value: Some(DynamicString::from(string_value)),
139 json_value: JsonValue::Number(num),
140 hash_value: ahash_str(&json_string),
141 ..DynamicValue::new()
142 }
143 }
144
145 #[must_use]
146 pub fn from_dynamic_array(value: Vec<DynamicValue>) -> Self {
147 let json_value =
148 JsonValue::Array(value.iter().map(|value| value.json_value.clone()).collect());
149 let string_value = DynamicString::from(json_value.to_string());
150 let hash_value = hashing::hash_one(
151 value
152 .iter()
153 .map(|value| value.hash_value)
154 .collect::<Vec<_>>(),
155 );
156
157 DynamicValue {
158 hash_value,
159 array_value: Some(value),
160 json_value,
161 string_value: Some(string_value),
162 ..DynamicValue::default()
163 }
164 }
165
166 #[must_use]
167 pub fn from_dynamic_object(value: HashMap<String, DynamicValue>) -> Self {
168 let json_value = JsonValue::Object(
169 value
170 .iter()
171 .map(|(key, value)| (key.clone(), value.json_value.clone()))
172 .collect::<JsonMap<String, JsonValue>>(),
173 );
174 let hash_value = hashing::hash_one(
175 value
176 .values()
177 .map(|value| value.hash_value)
178 .collect::<Vec<_>>(),
179 );
180
181 DynamicValue {
182 hash_value,
183 object_value: Some(value),
184 json_value,
185 ..DynamicValue::default()
186 }
187 }
188}
189
190impl PartialEq for DynamicValue {
191 fn eq(&self, other: &Self) -> bool {
192 self.null == other.null
193 && self.bool_value == other.bool_value
194 && self.int_value == other.int_value
195 && self.float_value == other.float_value
196 && self.string_value == other.string_value
197 && self.array_value == other.array_value
198 && self.object_value == other.object_value
199 }
200}
201
202impl Serialize for DynamicValue {
205 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
206 where
207 S: Serializer,
208 {
209 self.json_value.serialize(serializer)
210 }
211}
212
213impl<'de> Deserialize<'de> for DynamicValue {
214 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
215 where
216 D: Deserializer<'de>,
217 {
218 let json_value = JsonValue::deserialize(deserializer)?;
219 Ok(DynamicValue::from(json_value))
220 }
221}
222
223impl From<JsonValue> for DynamicValue {
226 fn from(json_value: JsonValue) -> Self {
227 let mut stringified_json_value = None;
229 let hash_value = if let JsonValue::String(s) = &json_value {
230 ahash_str(s)
231 } else {
232 let actual = json_value.to_string();
233 let hash = ahash_str(&actual);
234 stringified_json_value = Some(actual);
235 hash
236 };
237
238 match &json_value {
239 JsonValue::Null => DynamicValue {
240 null: Some(()),
241 json_value,
242 hash_value,
243 ..DynamicValue::new()
244 },
245
246 JsonValue::Bool(b) => DynamicValue {
247 bool_value: Some(*b),
248 string_value: Some(DynamicString::from(b.to_string())),
249 json_value,
250 hash_value,
251 ..DynamicValue::new()
252 },
253
254 JsonValue::Number(n) => {
255 let mut float_value = n.as_f64();
256 let mut int_value = n.as_i64();
257 if let (Some(f), None) = (float_value, int_value) {
258 let iv = f as i64;
259 if iv as f64 == f {
260 int_value = Some(iv);
261 }
262 } else if let (None, Some(i)) = (float_value, int_value) {
263 let fv = i as f64;
264 if fv as i64 == i {
265 float_value = Some(fv)
266 }
267 }
268
269 let string_value = float_value
270 .map(|f| f.to_string())
271 .or_else(|| int_value.map(|i| i.to_string()))
272 .or(stringified_json_value);
273
274 DynamicValue {
275 float_value,
276 int_value,
277 string_value: string_value.map(DynamicString::from),
278 json_value,
279 hash_value,
280 ..DynamicValue::new()
281 }
282 }
283
284 JsonValue::String(s) => {
285 let int_value = maybe_parse_i64(s);
286 let float_value = maybe_parse_f64(s);
287 let timestamp_value = try_parse_timestamp(s, int_value);
288 DynamicValue {
289 string_value: Some(DynamicString::from(s.clone())),
290 json_value,
291 timestamp_value,
292 int_value,
293 float_value,
294 hash_value,
295 ..DynamicValue::new()
296 }
297 }
298
299 JsonValue::Array(arr) => DynamicValue {
300 array_value: Some(arr.iter().map(|v| DynamicValue::from(v.clone())).collect()),
301 string_value: Some(DynamicString::from(
302 stringified_json_value.unwrap_or(json_value.to_string()),
303 )),
304 json_value,
305 hash_value,
306 ..DynamicValue::new()
307 },
308
309 JsonValue::Object(obj) => DynamicValue {
310 object_value: Some(
311 obj.into_iter()
312 .map(|(k, v)| (k.clone(), DynamicValue::from(v.clone())))
313 .collect(),
314 ),
315 json_value,
316 hash_value,
317 ..DynamicValue::new()
318 },
319 }
320 }
321}
322
323impl From<String> for DynamicValue {
324 fn from(value: String) -> Self {
325 Self::from_string(value)
326 }
327}
328
329impl From<&str> for DynamicValue {
330 fn from(value: &str) -> Self {
331 Self::from_string(value)
332 }
333}
334
335impl From<usize> for DynamicValue {
336 fn from(value: usize) -> Self {
337 Self::from(serde_json::Value::Number(serde_json::Number::from(value)))
338 }
339}
340
341impl From<i64> for DynamicValue {
342 fn from(value: i64) -> Self {
343 Self::from_i64(value)
344 }
345}
346
347impl From<i32> for DynamicValue {
348 fn from(value: i32) -> Self {
349 Self::from_i64(i64::from(value))
350 }
351}
352
353impl From<f64> for DynamicValue {
354 fn from(value: f64) -> Self {
355 Self::from_f64(value)
356 }
357}
358
359impl From<bool> for DynamicValue {
360 fn from(value: bool) -> Self {
361 Self::from_bool(value)
362 }
363}
364
365impl From<Vec<JsonValue>> for DynamicValue {
366 fn from(value: Vec<JsonValue>) -> Self {
367 DynamicValue::from(serde_json::Value::Array(value))
368 }
369}
370
371impl From<Vec<DynamicValue>> for DynamicValue {
372 fn from(value: Vec<DynamicValue>) -> Self {
373 Self::from_dynamic_array(value)
374 }
375}
376
377impl From<HashMap<String, DynamicValue>> for DynamicValue {
378 fn from(value: HashMap<String, DynamicValue>) -> Self {
379 Self::from_dynamic_object(value)
380 }
381}