1use rustc_hash::FxHashMap;
10use std::fmt;
11use std::ops::Index;
12
13#[cfg(feature = "serde")]
18use serde::{Deserialize, Serialize};
19
20#[derive(Debug, Clone, PartialEq)]
21#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
22pub enum Value {
24 Null,
26 Bool(bool),
28 Number(Number),
30 String(String),
32 Array(Vec<Value>),
34 Object(FxHashMap<String, Value>),
36}
37
38#[derive(Debug, Clone, PartialEq)]
43#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
44pub enum Number {
45 Integer(i64),
47 Float(f64),
49}
50
51impl Number {
52 #[inline(always)]
54 pub fn as_f64(&self) -> f64 {
55 match self {
56 Number::Integer(i) => *i as f64,
57 Number::Float(f) => *f,
58 }
59 }
60}
61
62impl Value {
63 #[inline(always)]
65 pub fn is_null(&self) -> bool {
66 matches!(self, Value::Null)
67 }
68
69 #[inline(always)]
71 pub fn is_bool(&self) -> bool {
72 matches!(self, Value::Bool(_))
73 }
74
75 #[inline(always)]
77 pub fn is_number(&self) -> bool {
78 matches!(self, Value::Number(_))
79 }
80
81 #[inline(always)]
83 pub fn is_string(&self) -> bool {
84 matches!(self, Value::String(_))
85 }
86
87 #[inline(always)]
89 pub fn is_array(&self) -> bool {
90 matches!(self, Value::Array(_))
91 }
92
93 #[inline(always)]
95 pub fn is_object(&self) -> bool {
96 matches!(self, Value::Object(_))
97 }
98
99 pub fn as_bool(&self) -> Option<bool> {
102 match self {
103 Value::Bool(b) => Some(*b),
104 _ => None,
105 }
106 }
107
108 pub fn as_i64(&self) -> Option<i64> {
111 match self {
112 Value::Number(Number::Integer(i)) => Some(*i),
113 Value::Number(Number::Float(f)) => {
114 if f.fract() == 0.0 && *f >= i64::MIN as f64 && *f <= i64::MAX as f64 {
115 Some(*f as i64)
116 } else {
117 None
118 }
119 }
120 _ => None,
121 }
122 }
123
124 pub fn as_f64(&self) -> Option<f64> {
127 match self {
128 Value::Number(Number::Integer(i)) => Some(*i as f64),
129 Value::Number(Number::Float(f)) => Some(*f),
130 _ => None,
131 }
132 }
133
134 pub fn as_str(&self) -> Option<&str> {
137 match self {
138 Value::String(s) => Some(s),
139 _ => None,
140 }
141 }
142
143 pub fn as_array(&self) -> Option<&Vec<Value>> {
146 match self {
147 Value::Array(a) => Some(a),
148 _ => None,
149 }
150 }
151
152 pub fn as_object(&self) -> Option<&FxHashMap<String, Value>> {
155 match self {
156 Value::Object(o) => Some(o),
157 _ => None,
158 }
159 }
160}
161
162impl fmt::Display for Value {
163 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164 match self {
165 Value::Null => write!(f, "null"),
166 Value::Bool(b) => write!(f, "{b}"),
167 Value::Number(n) => write!(f, "{n}"),
168 Value::String(s) => write!(f, "\"{s}\""),
169 Value::Array(arr) => {
170 write!(f, "[")?;
171 for (i, v) in arr.iter().enumerate() {
172 if i > 0 {
173 write!(f, ", ")?;
174 }
175 write!(f, "{v}")?;
176 }
177 write!(f, "]")
178 }
179 Value::Object(obj) => {
180 write!(f, "{{")?;
181 for (i, (k, v)) in obj.iter().enumerate() {
182 if i > 0 {
183 write!(f, ", ")?;
184 }
185 write!(f, "\"{k}\": {v}")?;
186 }
187 write!(f, "}}")
188 }
189 }
190 }
191}
192
193impl fmt::Display for Number {
194 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195 match self {
196 Number::Integer(i) => write!(f, "{i}"),
197 Number::Float(fl) => write!(f, "{fl}"),
198 }
199 }
200}
201
202impl Index<&str> for Value {
203 type Output = Value;
204
205 fn index(&self, index: &str) -> &Self::Output {
206 match self {
207 Value::Object(map) => map.get(index).unwrap_or(&Value::Null),
208 _ => &Value::Null,
209 }
210 }
211}
212
213impl Index<usize> for Value {
214 type Output = Value;
215
216 fn index(&self, index: usize) -> &Self::Output {
217 match self {
218 Value::Array(arr) => arr.get(index).unwrap_or(&Value::Null),
219 _ => &Value::Null,
220 }
221 }
222}
223
224#[cfg(test)]
225mod tests {
226 use super::*;
227
228 #[test]
229 fn test_value_is_type_checkers() {
230 let null_val = Value::Null;
231 let bool_val = Value::Bool(true);
232 let num_val = Value::Number(Number::Integer(42));
233 let str_val = Value::String("hello".to_string());
234 let arr_val = Value::Array(vec![Value::Null]);
235 let obj_val = Value::Object(FxHashMap::default());
236
237 assert!(null_val.is_null());
239 assert!(!bool_val.is_null());
240 assert!(!num_val.is_null());
241 assert!(!str_val.is_null());
242 assert!(!arr_val.is_null());
243 assert!(!obj_val.is_null());
244
245 assert!(!null_val.is_bool());
247 assert!(bool_val.is_bool());
248 assert!(!num_val.is_bool());
249 assert!(!str_val.is_bool());
250 assert!(!arr_val.is_bool());
251 assert!(!obj_val.is_bool());
252
253 assert!(!null_val.is_number());
255 assert!(!bool_val.is_number());
256 assert!(num_val.is_number());
257 assert!(!str_val.is_number());
258 assert!(!arr_val.is_number());
259 assert!(!obj_val.is_number());
260
261 assert!(!null_val.is_string());
263 assert!(!bool_val.is_string());
264 assert!(!num_val.is_string());
265 assert!(str_val.is_string());
266 assert!(!arr_val.is_string());
267 assert!(!obj_val.is_string());
268
269 assert!(!null_val.is_array());
271 assert!(!bool_val.is_array());
272 assert!(!num_val.is_array());
273 assert!(!str_val.is_array());
274 assert!(arr_val.is_array());
275 assert!(!obj_val.is_array());
276
277 assert!(!null_val.is_object());
279 assert!(!bool_val.is_object());
280 assert!(!num_val.is_object());
281 assert!(!str_val.is_object());
282 assert!(!arr_val.is_object());
283 assert!(obj_val.is_object());
284 }
285
286 #[test]
287 fn test_value_as_bool() {
288 let true_val = Value::Bool(true);
289 let false_val = Value::Bool(false);
290 let null_val = Value::Null;
291 let num_val = Value::Number(Number::Integer(42));
292
293 assert_eq!(true_val.as_bool(), Some(true));
294 assert_eq!(false_val.as_bool(), Some(false));
295 assert_eq!(null_val.as_bool(), None);
296 assert_eq!(num_val.as_bool(), None);
297 }
298
299 #[test]
300 fn test_value_as_i64() {
301 let int_val = Value::Number(Number::Integer(42));
302 let float_val = Value::Number(Number::Float(3.14));
303 let float_int_val = Value::Number(Number::Float(5.0));
304 let large_float_val = Value::Number(Number::Float(1e20));
305 let null_val = Value::Null;
306
307 assert_eq!(int_val.as_i64(), Some(42));
308 assert_eq!(float_val.as_i64(), None); assert_eq!(float_int_val.as_i64(), Some(5)); assert_eq!(large_float_val.as_i64(), None); assert_eq!(null_val.as_i64(), None);
312 }
313
314 #[test]
315 fn test_value_as_f64() {
316 let int_val = Value::Number(Number::Integer(42));
317 let float_val = Value::Number(Number::Float(3.14));
318 let null_val = Value::Null;
319 let str_val = Value::String("hello".to_string());
320
321 assert_eq!(int_val.as_f64(), Some(42.0));
322 assert_eq!(float_val.as_f64(), Some(3.14));
323 assert_eq!(null_val.as_f64(), None);
324 assert_eq!(str_val.as_f64(), None);
325 }
326
327 #[test]
328 fn test_value_as_str() {
329 let str_val = Value::String("hello".to_string());
330 let null_val = Value::Null;
331 let num_val = Value::Number(Number::Integer(42));
332
333 assert_eq!(str_val.as_str(), Some("hello"));
334 assert_eq!(null_val.as_str(), None);
335 assert_eq!(num_val.as_str(), None);
336 }
337
338 #[test]
339 fn test_value_as_array() {
340 let arr_val = Value::Array(vec![Value::Null, Value::Bool(true)]);
341 let null_val = Value::Null;
342 let str_val = Value::String("hello".to_string());
343
344 assert_eq!(arr_val.as_array(), Some(&vec![Value::Null, Value::Bool(true)]));
345 assert_eq!(null_val.as_array(), None);
346 assert_eq!(str_val.as_array(), None);
347 }
348
349 #[test]
350 fn test_value_as_object() {
351 let mut map = FxHashMap::default();
352 map.insert("key".to_string(), Value::String("value".to_string()));
353 let obj_val = Value::Object(map.clone());
354 let null_val = Value::Null;
355 let arr_val = Value::Array(vec![]);
356
357 assert_eq!(obj_val.as_object(), Some(&map));
358 assert_eq!(null_val.as_object(), None);
359 assert_eq!(arr_val.as_object(), None);
360 }
361
362 #[test]
363 fn test_value_index_str() {
364 let mut map = FxHashMap::default();
365 map.insert("name".to_string(), Value::String("John".to_string()));
366 map.insert("age".to_string(), Value::Number(Number::Integer(30)));
367 let obj_val = Value::Object(map);
368
369 assert_eq!(obj_val["name"], Value::String("John".to_string()));
370 assert_eq!(obj_val["age"], Value::Number(Number::Integer(30)));
371 assert_eq!(obj_val["missing"], Value::Null);
372
373 let arr_val = Value::Array(vec![]);
375 assert_eq!(arr_val["any"], Value::Null);
376 }
377
378 #[test]
379 fn test_value_index_usize() {
380 let arr_val = Value::Array(vec![
381 Value::String("first".to_string()),
382 Value::Number(Number::Integer(42)),
383 Value::Bool(true),
384 ]);
385
386 assert_eq!(arr_val[0], Value::String("first".to_string()));
387 assert_eq!(arr_val[1], Value::Number(Number::Integer(42)));
388 assert_eq!(arr_val[2], Value::Bool(true));
389 assert_eq!(arr_val[99], Value::Null); let obj_val = Value::Object(FxHashMap::default());
393 assert_eq!(obj_val[0], Value::Null);
394 }
395
396 #[test]
397 fn test_number_as_f64() {
398 let int_num = Number::Integer(42);
399 let float_num = Number::Float(3.14);
400
401 assert_eq!(int_num.as_f64(), 42.0);
402 assert_eq!(float_num.as_f64(), 3.14);
403 }
404
405 #[test]
406 fn test_value_display() {
407 let null_val = Value::Null;
408 let bool_val = Value::Bool(true);
409 let int_val = Value::Number(Number::Integer(42));
410 let float_val = Value::Number(Number::Float(3.14));
411 let str_val = Value::String("hello".to_string());
412
413 assert_eq!(null_val.to_string(), "null");
414 assert_eq!(bool_val.to_string(), "true");
415 assert_eq!(int_val.to_string(), "42");
416 assert_eq!(float_val.to_string(), "3.14");
417 assert_eq!(str_val.to_string(), "\"hello\"");
418 }
419
420 #[test]
421 fn test_value_display_array() {
422 let arr_val = Value::Array(vec![
423 Value::Number(Number::Integer(1)),
424 Value::Number(Number::Integer(2)),
425 Value::Number(Number::Integer(3)),
426 ]);
427
428 assert_eq!(arr_val.to_string(), "[1, 2, 3]");
429
430 let empty_arr = Value::Array(vec![]);
431 assert_eq!(empty_arr.to_string(), "[]");
432 }
433
434 #[test]
435 fn test_value_display_object() {
436 let mut map = FxHashMap::default();
437 map.insert("name".to_string(), Value::String("John".to_string()));
438 let obj_val = Value::Object(map);
439
440 assert_eq!(obj_val.to_string(), "{\"name\": \"John\"}");
441
442 let empty_obj = Value::Object(FxHashMap::default());
443 assert_eq!(empty_obj.to_string(), "{}");
444 }
445
446 #[test]
447 fn test_number_display() {
448 let int_num = Number::Integer(42);
449 let float_num = Number::Float(3.14);
450
451 assert_eq!(int_num.to_string(), "42");
452 assert_eq!(float_num.to_string(), "3.14");
453 }
454
455 #[test]
456 fn test_value_equality() {
457 let val1 = Value::Number(Number::Integer(42));
458 let val2 = Value::Number(Number::Integer(42));
459 let val3 = Value::Number(Number::Integer(43));
460
461 assert_eq!(val1, val2);
462 assert_ne!(val1, val3);
463 }
464
465 #[test]
466 fn test_number_equality() {
467 let int1 = Number::Integer(42);
468 let int2 = Number::Integer(42);
469 let int3 = Number::Integer(43);
470 let float1 = Number::Float(42.0);
471
472 assert_eq!(int1, int2);
473 assert_ne!(int1, int3);
474 assert_ne!(int1, float1); }
476
477 #[test]
478 fn test_as_i64_edge_cases() {
479 let max_int = Value::Number(Number::Integer(i64::MAX));
481 let min_int = Value::Number(Number::Integer(i64::MIN));
482
483 assert_eq!(max_int.as_i64(), Some(i64::MAX));
484 assert_eq!(min_int.as_i64(), Some(i64::MIN));
485
486 let max_float = Value::Number(Number::Float(i64::MAX as f64));
488 let min_float = Value::Number(Number::Float(i64::MIN as f64));
489 let too_large = Value::Number(Number::Float(1e20));
490 let negative_zero = Value::Number(Number::Float(-0.0));
491
492 assert_eq!(max_float.as_i64(), Some(i64::MAX));
493 assert_eq!(min_float.as_i64(), Some(i64::MIN));
494 assert_eq!(too_large.as_i64(), None);
495 assert_eq!(negative_zero.as_i64(), Some(0));
496 }
497}