1use super::number::NumberValue;
7use crate::arena::DataArena;
8use chrono::{DateTime, Duration, Utc};
9use std::cmp::Ordering;
10use std::fmt;
11
12#[derive(Debug, Clone, PartialEq)]
17pub enum DataValue<'a> {
18 Null,
20
21 Bool(bool),
23
24 Number(NumberValue),
26
27 String(&'a str),
29
30 Array(&'a [DataValue<'a>]),
32
33 Object(&'a [(&'a str, DataValue<'a>)]),
35
36 DateTime(DateTime<Utc>),
38
39 Duration(Duration),
41}
42
43impl<'a> DataValue<'a> {
44 pub fn null() -> Self {
46 DataValue::Null
47 }
48
49 pub fn bool(value: bool) -> Self {
51 DataValue::Bool(value)
52 }
53
54 pub fn integer(value: i64) -> Self {
56 DataValue::Number(NumberValue::Integer(value))
57 }
58
59 pub fn float(value: f64) -> Self {
61 DataValue::Number(NumberValue::from_f64(value))
62 }
63
64 pub fn string(arena: &'a DataArena, value: &str) -> Self {
68 if value.is_empty() {
69 DataValue::String(arena.empty_string())
71 } else {
72 DataValue::String(arena.alloc_str(value))
73 }
74 }
75
76 pub fn datetime(value: DateTime<Utc>) -> Self {
78 DataValue::DateTime(value)
79 }
80
81 pub fn duration(value: Duration) -> Self {
83 DataValue::Duration(value)
84 }
85
86 pub fn array(arena: &'a DataArena, values: &[DataValue<'a>]) -> Self {
91 if values.is_empty() {
92 DataValue::Array(arena.empty_array())
94 } else {
95 DataValue::Array(arena.alloc_data_value_slice(values))
97 }
98 }
99
100 pub fn object(arena: &'a DataArena, entries: &[(&'a str, DataValue<'a>)]) -> Self {
104 DataValue::Object(arena.alloc_object_entries(entries))
105 }
106
107 pub fn is_null(&self) -> bool {
109 matches!(self, DataValue::Null)
110 }
111
112 pub fn is_bool(&self) -> bool {
114 matches!(self, DataValue::Bool(_))
115 }
116
117 pub fn is_number(&self) -> bool {
119 matches!(self, DataValue::Number(_))
120 }
121
122 pub fn is_string(&self) -> bool {
124 matches!(self, DataValue::String(_))
125 }
126
127 pub fn is_array(&self) -> bool {
129 matches!(self, DataValue::Array(_))
130 }
131
132 pub fn is_object(&self) -> bool {
134 matches!(self, DataValue::Object(_))
135 }
136
137 pub fn is_datetime(&self) -> bool {
139 matches!(self, DataValue::DateTime(_))
140 }
141
142 pub fn is_duration(&self) -> bool {
144 matches!(self, DataValue::Duration(_))
145 }
146
147 pub fn as_bool(&self) -> Option<bool> {
149 match self {
150 DataValue::Bool(b) => Some(*b),
151 _ => None,
152 }
153 }
154
155 pub fn as_i64(&self) -> Option<i64> {
157 match self {
158 DataValue::Number(n) => n.as_i64(),
159 _ => None,
160 }
161 }
162
163 pub fn as_f64(&self) -> Option<f64> {
165 match self {
166 DataValue::Number(n) => Some(n.as_f64()),
167 _ => None,
168 }
169 }
170
171 pub fn as_str(&self) -> Option<&str> {
173 match self {
174 DataValue::String(s) => Some(s),
175 _ => None,
176 }
177 }
178
179 pub fn as_array(&self) -> Option<&[DataValue<'a>]> {
181 match self {
182 DataValue::Array(a) => Some(a),
183 _ => None,
184 }
185 }
186
187 pub fn as_datetime(&self) -> Option<&DateTime<Utc>> {
189 match self {
190 DataValue::DateTime(dt) => Some(dt),
191 _ => None,
192 }
193 }
194
195 pub fn as_duration(&self) -> Option<&Duration> {
197 match self {
198 DataValue::Duration(d) => Some(d),
199 _ => None,
200 }
201 }
202
203 pub fn as_object(&self) -> Option<&[(&'a str, DataValue<'a>)]> {
205 match self {
206 DataValue::Object(o) => Some(o),
207 _ => None,
208 }
209 }
210
211 #[inline]
222 pub fn coerce_to_bool(&self) -> bool {
223 match self {
224 DataValue::Bool(b) => *b,
226 DataValue::Null => false,
227
228 DataValue::Number(n) => {
230 if let NumberValue::Integer(i) = n {
232 *i != 0
233 } else {
234 n.as_f64() != 0.0
235 }
236 }
237
238 DataValue::String(s) => !s.is_empty(),
240
241 DataValue::Array(items) => !items.is_empty(),
243
244 DataValue::Object(items) => !items.is_empty(),
246
247 DataValue::DateTime(_) => true,
249
250 DataValue::Duration(d) => !d.is_zero(),
252 }
253 }
254
255 #[inline]
257 pub fn coerce_to_number(&self) -> Option<NumberValue> {
258 match self {
259 DataValue::Number(n) => Some(*n),
261 DataValue::Bool(b) => Some(NumberValue::Integer(if *b { 1 } else { 0 })),
262 DataValue::Null => Some(NumberValue::Integer(0)),
263
264 DataValue::String(s) => {
265 if s.is_empty() {
267 return Some(NumberValue::Integer(0));
268 }
269
270 let mut is_integer = true;
272 let mut value: i64 = 0;
273 let mut negative = false;
274 let bytes = s.as_bytes();
275
276 let mut i = 0;
278 if !bytes.is_empty() && bytes[0] == b'-' {
279 negative = true;
280 i = 1;
281 }
282
283 while i < bytes.len() {
285 let b = bytes[i];
286 if b.is_ascii_digit() {
287 if value > i64::MAX / 10 {
289 is_integer = false;
290 break;
291 }
292 value = value * 10 + (b - b'0') as i64;
293 } else {
294 is_integer = false;
295 break;
296 }
297 i += 1;
298 }
299
300 if is_integer {
301 if negative {
302 value = -value;
303 }
304 return Some(NumberValue::Integer(value));
305 }
306
307 if let Ok(i) = s.parse::<i64>() {
309 Some(NumberValue::Integer(i))
310 } else if let Ok(f) = s.parse::<f64>() {
311 Some(NumberValue::Float(f))
312 } else {
313 None
314 }
315 }
316
317 DataValue::DateTime(dt) => {
319 let timestamp = dt.timestamp_millis() as f64 / 1000.0;
320 Some(NumberValue::Float(timestamp))
321 }
322
323 DataValue::Duration(d) => {
325 let total_seconds = d.num_seconds();
326 Some(NumberValue::Integer(total_seconds))
327 }
328
329 DataValue::Array(_) => None,
330
331 DataValue::Object(_) => None,
332 }
333 }
334
335 pub fn coerce_to_string(&self, arena: &'a DataArena) -> DataValue<'a> {
337 match self {
338 DataValue::Null => DataValue::String(arena.alloc_str("null")),
339 DataValue::Bool(b) => {
340 DataValue::String(arena.alloc_str(if *b { "true" } else { "false" }))
341 }
342 DataValue::Number(n) => DataValue::String(arena.alloc_str(&n.to_string())),
343 DataValue::String(s) => DataValue::String(s),
344 DataValue::Array(a) => {
345 let mut result = String::new();
346 for (i, v) in a.iter().enumerate() {
347 if i > 0 {
348 result.push(',');
349 }
350 if let DataValue::String(s) = v.coerce_to_string(arena) {
351 result.push_str(s);
352 }
353 }
354 DataValue::String(arena.alloc_str(&result))
355 }
356 DataValue::Object(_) => DataValue::String(arena.alloc_str("[object Object]")),
357 DataValue::DateTime(dt) => {
358 let iso_string = dt.to_rfc3339();
360 DataValue::String(arena.alloc_str(&iso_string))
361 }
362 DataValue::Duration(d) => {
363 let days = d.num_days();
365 let hours = d.num_hours() % 24;
366 let minutes = d.num_minutes() % 60;
367 let seconds = d.num_seconds() % 60;
368 let formatted = format!("{}d:{}h:{}m:{}s", days, hours, minutes, seconds);
369 DataValue::String(arena.alloc_str(&formatted))
370 }
371 }
372 }
373
374 pub fn get(&self, key: &str) -> Option<&DataValue<'a>> {
376 match self {
377 DataValue::Object(entries) => entries
378 .binary_search_by_key(&key, |&(k, _)| k)
379 .ok()
380 .map(|idx| &entries[idx].1),
381 _ => None,
382 }
383 }
384
385 pub fn get_index(&self, index: usize) -> Option<&DataValue<'a>> {
387 match self {
388 DataValue::Array(elements) => elements.get(index),
389 _ => None,
390 }
391 }
392
393 pub fn type_name(&self) -> &'static str {
395 match self {
396 DataValue::Null => "null",
397 DataValue::Bool(_) => "boolean",
398 DataValue::Number(_) => "number",
399 DataValue::String(_) => "string",
400 DataValue::Array(_) => "array",
401 DataValue::Object(_) => "object",
402 DataValue::DateTime(_) => "datetime",
403 DataValue::Duration(_) => "duration",
404 }
405 }
406
407 pub fn equals(&self, other: &DataValue<'a>) -> bool {
409 match (self, other) {
410 (DataValue::Null, DataValue::Null) => true,
412 (DataValue::Bool(a), DataValue::Bool(b)) => a == b,
413 (DataValue::Number(a), DataValue::Number(b)) => a == b,
414
415 (DataValue::String(a), DataValue::String(b)) => {
417 if std::ptr::eq(*a as *const str, *b as *const str) {
419 return true;
420 }
421
422 if a.len() != b.len() {
424 return false;
425 }
426
427 a == b
429 }
430
431 (DataValue::DateTime(a), DataValue::DateTime(b)) => a == b,
433 (DataValue::Duration(a), DataValue::Duration(b)) => a == b,
434
435 (DataValue::Null, DataValue::Bool(b)) => !b,
437 (DataValue::Bool(a), DataValue::Null) => !a,
438
439 (DataValue::Number(a), DataValue::String(_)) => {
440 match other.coerce_to_number() {
441 Some(b_value) => {
442 let b_num = b_value.as_f64();
443 let a_num = a.as_f64();
444 (a_num - b_num).abs() < f64::EPSILON
446 }
447 None => false, }
449 }
450 (DataValue::String(_), DataValue::Number(b)) => {
451 match self.coerce_to_number() {
452 Some(a_value) => {
453 let a_num = a_value.as_f64();
454 let b_num = b.as_f64();
455 (a_num - b_num).abs() < f64::EPSILON
457 }
458 None => false, }
460 }
461
462 (DataValue::Array(a), DataValue::Array(b)) => {
464 if a.len() != b.len() {
465 return false;
466 }
467 a.iter()
468 .zip(b.iter())
469 .all(|(a_item, b_item)| a_item.equals(b_item))
470 }
471 (DataValue::Object(a), DataValue::Object(b)) => {
472 if a.len() != b.len() {
474 return false;
475 }
476
477 for (a_key, a_val) in *a {
479 let found_pair = b
480 .iter()
481 .any(|(b_key, b_val)| *a_key == *b_key && a_val.equals(b_val));
482 if !found_pair {
483 return false;
484 }
485 }
486
487 true
489 }
490
491 _ => false,
493 }
494 }
495
496 pub fn strict_equals(&self, other: &DataValue<'a>) -> bool {
498 match (self, other) {
499 (DataValue::Null, DataValue::Null) => true,
500 (DataValue::Bool(a), DataValue::Bool(b)) => a == b,
501 (DataValue::Number(a), DataValue::Number(b)) => a == b,
502 (DataValue::String(a), DataValue::String(b)) => a == b,
503 (DataValue::DateTime(a), DataValue::DateTime(b)) => a == b,
504 (DataValue::Duration(a), DataValue::Duration(b)) => a == b,
505 (DataValue::Array(a), DataValue::Array(b)) => {
506 if a.len() != b.len() {
507 return false;
508 }
509 a.iter()
510 .zip(b.iter())
511 .all(|(a_item, b_item)| a_item.strict_equals(b_item))
512 }
513 (DataValue::Object(a), DataValue::Object(b)) => {
514 if a.len() != b.len() {
515 return false;
516 }
517
518 for (a_key, a_value) in *a {
520 let mut found = false;
521 for (b_key, b_value) in *b {
522 if a_key == b_key {
523 if !a_value.strict_equals(b_value) {
524 return false;
525 }
526 found = true;
527 break;
528 }
529 }
530 if !found {
531 return false;
532 }
533 }
534 true
535 }
536 _ => false, }
538 }
539}
540
541impl PartialOrd for DataValue<'_> {
542 #[inline]
543 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
544 match (self, other) {
545 (DataValue::Number(a), DataValue::Number(b)) => a.partial_cmp(b),
547 (DataValue::String(a), DataValue::String(b)) => {
548 if std::ptr::eq(*a as *const str, *b as *const str) {
550 return Some(Ordering::Equal);
551 }
552
553 a.partial_cmp(b)
555 }
556 (DataValue::Bool(a), DataValue::Bool(b)) => a.partial_cmp(b),
557 (DataValue::Null, DataValue::Null) => Some(Ordering::Equal),
558
559 (DataValue::DateTime(a), DataValue::DateTime(b)) => a.partial_cmp(b),
561 (DataValue::Duration(a), DataValue::Duration(b)) => a.partial_cmp(b),
562
563 (DataValue::Array(a), DataValue::Array(b)) => {
564 if a.is_empty() && b.is_empty() {
566 return Some(Ordering::Equal);
567 }
568
569 if a.len() != b.len() {
571 return a.len().partial_cmp(&b.len());
572 }
573
574 for i in 0..a.len() {
576 match a[i].partial_cmp(&b[i]) {
577 Some(Ordering::Equal) => continue,
578 other => return other,
579 }
580 }
581 Some(Ordering::Equal)
582 }
583
584 (DataValue::Number(a), DataValue::String(b)) => {
586 if let Ok(b_num) = b.parse::<f64>() {
587 let a_f64 = match a {
588 NumberValue::Integer(i) => *i as f64,
589 NumberValue::Float(f) => *f,
590 };
591
592 if a_f64 > b_num {
593 Some(Ordering::Greater)
594 } else if a_f64 < b_num {
595 Some(Ordering::Less)
596 } else {
597 Some(Ordering::Equal)
598 }
599 } else {
600 None
601 }
602 }
603 (DataValue::String(a), DataValue::Number(b)) => {
604 if let Ok(a_num) = a.parse::<f64>() {
605 let b_f64 = match b {
606 NumberValue::Integer(i) => *i as f64,
607 NumberValue::Float(f) => *f,
608 };
609
610 if a_num > b_f64 {
611 Some(Ordering::Greater)
612 } else if a_num < b_f64 {
613 Some(Ordering::Less)
614 } else {
615 Some(Ordering::Equal)
616 }
617 } else {
618 None
619 }
620 }
621
622 _ => None,
624 }
625 }
626}
627
628impl fmt::Display for DataValue<'_> {
629 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
630 match self {
631 DataValue::Null => write!(f, "null"),
632 DataValue::Bool(b) => write!(f, "{}", b),
633 DataValue::Number(n) => write!(f, "{}", n),
634 DataValue::String(s) => write!(f, "\"{}\"", s.replace('"', "\\\"")),
635 DataValue::Array(a) => {
636 write!(f, "[")?;
637 for (i, v) in a.iter().enumerate() {
638 if i > 0 {
639 write!(f, ", ")?;
640 }
641 write!(f, "{}", v)?;
642 }
643 write!(f, "]")
644 }
645 DataValue::Object(o) => {
646 write!(f, "{{")?;
647 for (i, (k, v)) in o.iter().enumerate() {
648 if i > 0 {
649 write!(f, ", ")?;
650 }
651 write!(f, "\"{}\": {}", k, v)?;
652 }
653 write!(f, "}}")
654 }
655 DataValue::DateTime(dt) => {
656 write!(f, "\"{}\"", dt.to_rfc3339())
657 }
658 DataValue::Duration(d) => {
659 let days = d.num_days();
660 let hours = d.num_hours() % 24;
661 let minutes = d.num_minutes() % 60;
662 let seconds = d.num_seconds() % 60;
663 write!(f, "{}d:{}h:{}m:{}s", days, hours, minutes, seconds)
664 }
665 }
666 }
667}
668
669#[cfg(test)]
670mod tests {
671 use super::*;
672 use crate::arena::DataArena;
673 use chrono::TimeZone;
674
675 #[test]
676 fn test_data_value_creation() {
677 let arena = DataArena::new();
678
679 let null = DataValue::null();
680 let boolean = DataValue::bool(true);
681 let integer = DataValue::integer(42);
682 let float = DataValue::float(3.14);
683 let string = DataValue::string(&arena, "hello");
684
685 assert!(null.is_null());
686 assert!(boolean.is_bool());
687 assert!(integer.is_number());
688 assert!(float.is_number());
689 assert!(string.is_string());
690
691 assert_eq!(boolean.as_bool(), Some(true));
692 assert_eq!(integer.as_i64(), Some(42));
693 assert_eq!(float.as_f64(), Some(3.14));
694 assert_eq!(string.as_str(), Some("hello"));
695 }
696
697 #[test]
698 fn test_datetime_and_duration() {
699 let dt = Utc.with_ymd_and_hms(2022, 7, 6, 13, 20, 6).unwrap();
701 let dt_value = DataValue::datetime(dt);
702
703 assert!(dt_value.is_datetime());
704 assert_eq!(dt_value.as_datetime(), Some(&dt));
705
706 let duration =
708 Duration::days(1) + Duration::hours(2) + Duration::minutes(3) + Duration::seconds(4);
709 let duration_value = DataValue::duration(duration);
710
711 assert!(duration_value.is_duration());
712 assert_eq!(duration_value.as_duration(), Some(&duration));
713 }
714
715 #[test]
716 fn test_array_and_object() {
717 let arena = DataArena::new();
718
719 let array = DataValue::array(
721 &arena,
722 &[
723 DataValue::integer(1),
724 DataValue::integer(2),
725 DataValue::integer(3),
726 ],
727 );
728
729 assert!(array.is_array());
730 assert_eq!(array.as_array().unwrap().len(), 3);
731 assert_eq!(array.get_index(1).unwrap().as_i64(), Some(2));
732
733 let key1 = arena.intern_str("a");
735 let key2 = arena.intern_str("b");
736
737 let object = DataValue::object(
738 &arena,
739 &[(key1, DataValue::integer(1)), (key2, DataValue::integer(2))],
740 );
741
742 assert!(object.is_object());
743 assert_eq!(object.as_object().unwrap().len(), 2);
744 assert_eq!(object.get("a").unwrap().as_i64(), Some(1));
745 }
746
747 #[test]
748 fn test_coercion() {
749 let arena = DataArena::new();
750
751 assert!(!DataValue::null().coerce_to_bool());
753 assert!(DataValue::bool(true).coerce_to_bool());
754 assert!(!DataValue::integer(0).coerce_to_bool());
755 assert!(DataValue::integer(1).coerce_to_bool());
756 assert!(!DataValue::string(&arena, "").coerce_to_bool());
757 assert!(DataValue::string(&arena, "hello").coerce_to_bool());
758
759 let dt = Utc.with_ymd_and_hms(2022, 7, 6, 13, 20, 6).unwrap();
761 assert!(DataValue::datetime(dt).coerce_to_bool());
762
763 let duration = Duration::seconds(0);
764 assert!(!DataValue::duration(duration).coerce_to_bool());
765
766 let non_zero_duration = Duration::seconds(10);
767 assert!(DataValue::duration(non_zero_duration).coerce_to_bool());
768
769 assert_eq!(
771 DataValue::null().coerce_to_number(),
772 Some(NumberValue::Integer(0))
773 );
774 assert_eq!(
775 DataValue::bool(true).coerce_to_number(),
776 Some(NumberValue::Integer(1))
777 );
778 assert_eq!(
779 DataValue::string(&arena, "42").coerce_to_number(),
780 Some(NumberValue::Integer(42))
781 );
782 assert_eq!(
783 DataValue::string(&arena, "3.14").coerce_to_number(),
784 Some(NumberValue::Float(3.14))
785 );
786
787 let dt = Utc.with_ymd_and_hms(2022, 7, 6, 13, 20, 6).unwrap();
789 let dt_num = DataValue::datetime(dt).coerce_to_number();
790 assert!(dt_num.is_some());
791
792 let duration = Duration::seconds(93784); assert_eq!(
794 DataValue::duration(duration).coerce_to_number(),
795 Some(NumberValue::Integer(93784))
796 );
797
798 assert_eq!(
800 DataValue::null().coerce_to_string(&arena).as_str(),
801 Some("null")
802 );
803 assert_eq!(
804 DataValue::bool(true).coerce_to_string(&arena).as_str(),
805 Some("true")
806 );
807 assert_eq!(
808 DataValue::integer(42).coerce_to_string(&arena).as_str(),
809 Some("42")
810 );
811
812 let dt = Utc.with_ymd_and_hms(2022, 7, 6, 13, 20, 6).unwrap();
814 let dt_value = DataValue::datetime(dt).coerce_to_string(&arena);
815 let dt_str = dt_value.as_str();
816 assert!(dt_str.is_some());
817 assert!(dt_str.unwrap().contains("2022-07-06T13:20:06"));
818
819 let duration =
820 Duration::days(1) + Duration::hours(2) + Duration::minutes(3) + Duration::seconds(4);
821 let dur_value = DataValue::duration(duration).coerce_to_string(&arena);
822 let dur_str = dur_value.as_str();
823 assert_eq!(dur_str, Some("1d:2h:3m:4s"));
824 }
825
826 #[test]
827 fn test_comparison() {
828 let arena = DataArena::new();
829
830 assert!(DataValue::null() == DataValue::null());
832 assert!(DataValue::bool(true) > DataValue::bool(false));
833 assert!(DataValue::integer(5) > DataValue::integer(3));
834 assert!(DataValue::float(3.14) > DataValue::float(2.71));
835 assert!(DataValue::string(&arena, "hello") == DataValue::string(&arena, "hello"));
836 assert!(DataValue::string(&arena, "world") > DataValue::string(&arena, "hello"));
837
838 let dt1 = Utc.with_ymd_and_hms(2022, 7, 6, 13, 20, 6).unwrap();
840 let dt2 = Utc.with_ymd_and_hms(2022, 7, 7, 13, 20, 6).unwrap();
841
842 assert!(DataValue::datetime(dt1) < DataValue::datetime(dt2));
843 assert!(DataValue::datetime(dt2) > DataValue::datetime(dt1));
844 assert!(DataValue::datetime(dt1) == DataValue::datetime(dt1));
845
846 let dur1 = Duration::days(1);
848 let dur2 = Duration::days(2);
849
850 assert!(DataValue::duration(dur1) < DataValue::duration(dur2));
851 assert!(DataValue::duration(dur2) > DataValue::duration(dur1));
852 assert!(DataValue::duration(dur1) == DataValue::duration(dur1));
853
854 assert!(DataValue::integer(42) == DataValue::float(42.0));
856
857 let array1 = DataValue::array(&arena, &[DataValue::integer(1), DataValue::integer(2)]);
859 let array2 = DataValue::array(&arena, &[DataValue::integer(1), DataValue::integer(3)]);
860 assert!(array1 < array2);
861 }
862}