1use arcstr::ArcStr;
8use serde::{Deserialize, Serialize};
9use std::collections::BTreeMap;
10use std::fmt;
11use std::hash::{Hash, Hasher};
12use std::sync::Arc;
13
14use super::Timestamp;
15
16#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
21pub struct PropertyKey(ArcStr);
22
23impl PropertyKey {
24 #[must_use]
26 pub fn new(s: impl Into<ArcStr>) -> Self {
27 Self(s.into())
28 }
29
30 #[must_use]
32 pub fn as_str(&self) -> &str {
33 &self.0
34 }
35}
36
37impl fmt::Debug for PropertyKey {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 write!(f, "PropertyKey({:?})", self.0)
40 }
41}
42
43impl fmt::Display for PropertyKey {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 write!(f, "{}", self.0)
46 }
47}
48
49impl From<&str> for PropertyKey {
50 fn from(s: &str) -> Self {
51 Self::new(s)
52 }
53}
54
55impl From<String> for PropertyKey {
56 fn from(s: String) -> Self {
57 Self::new(s)
58 }
59}
60
61impl AsRef<str> for PropertyKey {
62 fn as_ref(&self) -> &str {
63 &self.0
64 }
65}
66
67#[derive(Clone, PartialEq, Serialize, Deserialize)]
87pub enum Value {
88 Null,
90
91 Bool(bool),
93
94 Int64(i64),
96
97 Float64(f64),
99
100 String(ArcStr),
102
103 Bytes(Arc<[u8]>),
105
106 Timestamp(Timestamp),
108
109 List(Arc<[Value]>),
111
112 Map(Arc<BTreeMap<PropertyKey, Value>>),
114}
115
116impl Value {
117 #[inline]
119 #[must_use]
120 pub const fn is_null(&self) -> bool {
121 matches!(self, Value::Null)
122 }
123
124 #[inline]
126 #[must_use]
127 pub const fn as_bool(&self) -> Option<bool> {
128 match self {
129 Value::Bool(b) => Some(*b),
130 _ => None,
131 }
132 }
133
134 #[inline]
136 #[must_use]
137 pub const fn as_int64(&self) -> Option<i64> {
138 match self {
139 Value::Int64(i) => Some(*i),
140 _ => None,
141 }
142 }
143
144 #[inline]
146 #[must_use]
147 pub const fn as_float64(&self) -> Option<f64> {
148 match self {
149 Value::Float64(f) => Some(*f),
150 _ => None,
151 }
152 }
153
154 #[inline]
156 #[must_use]
157 pub fn as_str(&self) -> Option<&str> {
158 match self {
159 Value::String(s) => Some(s),
160 _ => None,
161 }
162 }
163
164 #[inline]
166 #[must_use]
167 pub fn as_bytes(&self) -> Option<&[u8]> {
168 match self {
169 Value::Bytes(b) => Some(b),
170 _ => None,
171 }
172 }
173
174 #[inline]
176 #[must_use]
177 pub const fn as_timestamp(&self) -> Option<Timestamp> {
178 match self {
179 Value::Timestamp(t) => Some(*t),
180 _ => None,
181 }
182 }
183
184 #[inline]
186 #[must_use]
187 pub fn as_list(&self) -> Option<&[Value]> {
188 match self {
189 Value::List(l) => Some(l),
190 _ => None,
191 }
192 }
193
194 #[inline]
196 #[must_use]
197 pub fn as_map(&self) -> Option<&BTreeMap<PropertyKey, Value>> {
198 match self {
199 Value::Map(m) => Some(m),
200 _ => None,
201 }
202 }
203
204 #[must_use]
206 pub const fn type_name(&self) -> &'static str {
207 match self {
208 Value::Null => "NULL",
209 Value::Bool(_) => "BOOL",
210 Value::Int64(_) => "INT64",
211 Value::Float64(_) => "FLOAT64",
212 Value::String(_) => "STRING",
213 Value::Bytes(_) => "BYTES",
214 Value::Timestamp(_) => "TIMESTAMP",
215 Value::List(_) => "LIST",
216 Value::Map(_) => "MAP",
217 }
218 }
219
220 #[must_use]
222 pub fn serialize(&self) -> Vec<u8> {
223 bincode::serde::encode_to_vec(self, bincode::config::standard())
224 .expect("Value serialization should not fail")
225 }
226
227 pub fn deserialize(bytes: &[u8]) -> Result<Self, bincode::error::DecodeError> {
233 let (value, _) = bincode::serde::decode_from_slice(bytes, bincode::config::standard())?;
234 Ok(value)
235 }
236}
237
238impl fmt::Debug for Value {
239 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
240 match self {
241 Value::Null => write!(f, "Null"),
242 Value::Bool(b) => write!(f, "Bool({b})"),
243 Value::Int64(i) => write!(f, "Int64({i})"),
244 Value::Float64(fl) => write!(f, "Float64({fl})"),
245 Value::String(s) => write!(f, "String({s:?})"),
246 Value::Bytes(b) => write!(f, "Bytes([{}; {} bytes])", b.first().unwrap_or(&0), b.len()),
247 Value::Timestamp(t) => write!(f, "Timestamp({t:?})"),
248 Value::List(l) => write!(f, "List({l:?})"),
249 Value::Map(m) => write!(f, "Map({m:?})"),
250 }
251 }
252}
253
254impl fmt::Display for Value {
255 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
256 match self {
257 Value::Null => write!(f, "NULL"),
258 Value::Bool(b) => write!(f, "{b}"),
259 Value::Int64(i) => write!(f, "{i}"),
260 Value::Float64(fl) => write!(f, "{fl}"),
261 Value::String(s) => write!(f, "{s:?}"),
262 Value::Bytes(b) => write!(f, "<bytes: {} bytes>", b.len()),
263 Value::Timestamp(t) => write!(f, "{t}"),
264 Value::List(l) => {
265 write!(f, "[")?;
266 for (i, v) in l.iter().enumerate() {
267 if i > 0 {
268 write!(f, ", ")?;
269 }
270 write!(f, "{v}")?;
271 }
272 write!(f, "]")
273 }
274 Value::Map(m) => {
275 write!(f, "{{")?;
276 for (i, (k, v)) in m.iter().enumerate() {
277 if i > 0 {
278 write!(f, ", ")?;
279 }
280 write!(f, "{k}: {v}")?;
281 }
282 write!(f, "}}")
283 }
284 }
285 }
286}
287
288impl From<bool> for Value {
290 fn from(b: bool) -> Self {
291 Value::Bool(b)
292 }
293}
294
295impl From<i64> for Value {
296 fn from(i: i64) -> Self {
297 Value::Int64(i)
298 }
299}
300
301impl From<i32> for Value {
302 fn from(i: i32) -> Self {
303 Value::Int64(i64::from(i))
304 }
305}
306
307impl From<f64> for Value {
308 fn from(f: f64) -> Self {
309 Value::Float64(f)
310 }
311}
312
313impl From<f32> for Value {
314 fn from(f: f32) -> Self {
315 Value::Float64(f64::from(f))
316 }
317}
318
319impl From<&str> for Value {
320 fn from(s: &str) -> Self {
321 Value::String(s.into())
322 }
323}
324
325impl From<String> for Value {
326 fn from(s: String) -> Self {
327 Value::String(s.into())
328 }
329}
330
331impl From<ArcStr> for Value {
332 fn from(s: ArcStr) -> Self {
333 Value::String(s)
334 }
335}
336
337impl From<Vec<u8>> for Value {
338 fn from(b: Vec<u8>) -> Self {
339 Value::Bytes(b.into())
340 }
341}
342
343impl From<&[u8]> for Value {
344 fn from(b: &[u8]) -> Self {
345 Value::Bytes(b.into())
346 }
347}
348
349impl From<Timestamp> for Value {
350 fn from(t: Timestamp) -> Self {
351 Value::Timestamp(t)
352 }
353}
354
355impl<T: Into<Value>> From<Vec<T>> for Value {
356 fn from(v: Vec<T>) -> Self {
357 Value::List(v.into_iter().map(Into::into).collect())
358 }
359}
360
361impl<T: Into<Value>> From<Option<T>> for Value {
362 fn from(opt: Option<T>) -> Self {
363 match opt {
364 Some(v) => v.into(),
365 None => Value::Null,
366 }
367 }
368}
369
370#[derive(Clone, Debug)]
382pub struct HashableValue(pub Value);
383
384#[derive(Clone, Debug)]
416pub enum OrderableValue {
417 Int64(i64),
419 Float64(OrderedFloat64),
421 String(ArcStr),
423 Bool(bool),
425 Timestamp(Timestamp),
427}
428
429#[derive(Clone, Copy, Debug)]
434pub struct OrderedFloat64(pub f64);
435
436impl OrderedFloat64 {
437 #[must_use]
439 pub const fn new(f: f64) -> Self {
440 Self(f)
441 }
442
443 #[must_use]
445 pub const fn get(&self) -> f64 {
446 self.0
447 }
448}
449
450impl PartialEq for OrderedFloat64 {
451 fn eq(&self, other: &Self) -> bool {
452 match (self.0.is_nan(), other.0.is_nan()) {
454 (true, true) => true,
455 (true, false) | (false, true) => false,
456 (false, false) => self.0 == other.0,
457 }
458 }
459}
460
461impl Eq for OrderedFloat64 {}
462
463impl PartialOrd for OrderedFloat64 {
464 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
465 Some(self.cmp(other))
466 }
467}
468
469impl Ord for OrderedFloat64 {
470 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
471 match (self.0.is_nan(), other.0.is_nan()) {
473 (true, true) => std::cmp::Ordering::Equal,
474 (true, false) => std::cmp::Ordering::Greater,
475 (false, true) => std::cmp::Ordering::Less,
476 (false, false) => {
477 self.0
479 .partial_cmp(&other.0)
480 .unwrap_or(std::cmp::Ordering::Equal)
481 }
482 }
483 }
484}
485
486impl Hash for OrderedFloat64 {
487 fn hash<H: Hasher>(&self, state: &mut H) {
488 self.0.to_bits().hash(state);
489 }
490}
491
492impl From<f64> for OrderedFloat64 {
493 fn from(f: f64) -> Self {
494 Self(f)
495 }
496}
497
498impl OrderableValue {
499 #[must_use]
504 pub fn try_from(value: &Value) -> Option<Self> {
505 match value {
506 Value::Int64(i) => Some(Self::Int64(*i)),
507 Value::Float64(f) => Some(Self::Float64(OrderedFloat64(*f))),
508 Value::String(s) => Some(Self::String(s.clone())),
509 Value::Bool(b) => Some(Self::Bool(*b)),
510 Value::Timestamp(t) => Some(Self::Timestamp(*t)),
511 Value::Null | Value::Bytes(_) | Value::List(_) | Value::Map(_) => None,
512 }
513 }
514
515 #[must_use]
517 pub fn into_value(self) -> Value {
518 match self {
519 Self::Int64(i) => Value::Int64(i),
520 Self::Float64(f) => Value::Float64(f.0),
521 Self::String(s) => Value::String(s),
522 Self::Bool(b) => Value::Bool(b),
523 Self::Timestamp(t) => Value::Timestamp(t),
524 }
525 }
526
527 #[must_use]
529 pub const fn as_i64(&self) -> Option<i64> {
530 match self {
531 Self::Int64(i) => Some(*i),
532 _ => None,
533 }
534 }
535
536 #[must_use]
538 pub const fn as_f64(&self) -> Option<f64> {
539 match self {
540 Self::Float64(f) => Some(f.0),
541 _ => None,
542 }
543 }
544
545 #[must_use]
547 pub fn as_str(&self) -> Option<&str> {
548 match self {
549 Self::String(s) => Some(s),
550 _ => None,
551 }
552 }
553}
554
555impl PartialEq for OrderableValue {
556 fn eq(&self, other: &Self) -> bool {
557 match (self, other) {
558 (Self::Int64(a), Self::Int64(b)) => a == b,
559 (Self::Float64(a), Self::Float64(b)) => a == b,
560 (Self::String(a), Self::String(b)) => a == b,
561 (Self::Bool(a), Self::Bool(b)) => a == b,
562 (Self::Timestamp(a), Self::Timestamp(b)) => a == b,
563 (Self::Int64(a), Self::Float64(b)) => (*a as f64) == b.0,
565 (Self::Float64(a), Self::Int64(b)) => a.0 == (*b as f64),
566 _ => false,
567 }
568 }
569}
570
571impl Eq for OrderableValue {}
572
573impl PartialOrd for OrderableValue {
574 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
575 Some(self.cmp(other))
576 }
577}
578
579impl Ord for OrderableValue {
580 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
581 match (self, other) {
582 (Self::Int64(a), Self::Int64(b)) => a.cmp(b),
583 (Self::Float64(a), Self::Float64(b)) => a.cmp(b),
584 (Self::String(a), Self::String(b)) => a.cmp(b),
585 (Self::Bool(a), Self::Bool(b)) => a.cmp(b),
586 (Self::Timestamp(a), Self::Timestamp(b)) => a.cmp(b),
587 (Self::Int64(a), Self::Float64(b)) => OrderedFloat64(*a as f64).cmp(b),
589 (Self::Float64(a), Self::Int64(b)) => a.cmp(&OrderedFloat64(*b as f64)),
590 _ => self.type_ordinal().cmp(&other.type_ordinal()),
593 }
594 }
595}
596
597impl OrderableValue {
598 const fn type_ordinal(&self) -> u8 {
600 match self {
601 Self::Bool(_) => 0,
602 Self::Int64(_) => 1,
603 Self::Float64(_) => 2,
604 Self::String(_) => 3,
605 Self::Timestamp(_) => 4,
606 }
607 }
608}
609
610impl Hash for OrderableValue {
611 fn hash<H: Hasher>(&self, state: &mut H) {
612 std::mem::discriminant(self).hash(state);
613 match self {
614 Self::Int64(i) => i.hash(state),
615 Self::Float64(f) => f.hash(state),
616 Self::String(s) => s.hash(state),
617 Self::Bool(b) => b.hash(state),
618 Self::Timestamp(t) => t.hash(state),
619 }
620 }
621}
622
623impl HashableValue {
624 #[must_use]
626 pub fn new(value: Value) -> Self {
627 Self(value)
628 }
629
630 #[must_use]
632 pub fn inner(&self) -> &Value {
633 &self.0
634 }
635
636 #[must_use]
638 pub fn into_inner(self) -> Value {
639 self.0
640 }
641}
642
643impl Hash for HashableValue {
644 fn hash<H: Hasher>(&self, state: &mut H) {
645 std::mem::discriminant(&self.0).hash(state);
647
648 match &self.0 {
649 Value::Null => {}
650 Value::Bool(b) => b.hash(state),
651 Value::Int64(i) => i.hash(state),
652 Value::Float64(f) => {
653 f.to_bits().hash(state);
655 }
656 Value::String(s) => s.hash(state),
657 Value::Bytes(b) => b.hash(state),
658 Value::Timestamp(t) => t.hash(state),
659 Value::List(l) => {
660 l.len().hash(state);
661 for v in l.iter() {
662 HashableValue(v.clone()).hash(state);
663 }
664 }
665 Value::Map(m) => {
666 m.len().hash(state);
667 for (k, v) in m.iter() {
668 k.hash(state);
669 HashableValue(v.clone()).hash(state);
670 }
671 }
672 }
673 }
674}
675
676impl PartialEq for HashableValue {
677 fn eq(&self, other: &Self) -> bool {
678 match (&self.0, &other.0) {
679 (Value::Float64(a), Value::Float64(b)) => {
680 a.to_bits() == b.to_bits()
682 }
683 (Value::List(a), Value::List(b)) => {
684 if a.len() != b.len() {
685 return false;
686 }
687 a.iter()
688 .zip(b.iter())
689 .all(|(x, y)| HashableValue(x.clone()) == HashableValue(y.clone()))
690 }
691 (Value::Map(a), Value::Map(b)) => {
692 if a.len() != b.len() {
693 return false;
694 }
695 a.iter().all(|(k, v)| {
696 b.get(k)
697 .is_some_and(|bv| HashableValue(v.clone()) == HashableValue(bv.clone()))
698 })
699 }
700 _ => self.0 == other.0,
702 }
703 }
704}
705
706impl Eq for HashableValue {}
707
708impl From<Value> for HashableValue {
709 fn from(value: Value) -> Self {
710 Self(value)
711 }
712}
713
714impl From<HashableValue> for Value {
715 fn from(hv: HashableValue) -> Self {
716 hv.0
717 }
718}
719
720#[cfg(test)]
721mod tests {
722 use super::*;
723
724 #[test]
725 fn test_value_type_checks() {
726 assert!(Value::Null.is_null());
727 assert!(!Value::Bool(true).is_null());
728
729 assert_eq!(Value::Bool(true).as_bool(), Some(true));
730 assert_eq!(Value::Bool(false).as_bool(), Some(false));
731 assert_eq!(Value::Int64(42).as_bool(), None);
732
733 assert_eq!(Value::Int64(42).as_int64(), Some(42));
734 assert_eq!(Value::String("test".into()).as_int64(), None);
735
736 assert_eq!(Value::Float64(1.234).as_float64(), Some(1.234));
737 assert_eq!(Value::String("hello".into()).as_str(), Some("hello"));
738 }
739
740 #[test]
741 fn test_value_from_conversions() {
742 let v: Value = true.into();
743 assert_eq!(v.as_bool(), Some(true));
744
745 let v: Value = 42i64.into();
746 assert_eq!(v.as_int64(), Some(42));
747
748 let v: Value = 1.234f64.into();
749 assert_eq!(v.as_float64(), Some(1.234));
750
751 let v: Value = "hello".into();
752 assert_eq!(v.as_str(), Some("hello"));
753
754 let v: Value = vec![1u8, 2, 3].into();
755 assert_eq!(v.as_bytes(), Some(&[1u8, 2, 3][..]));
756 }
757
758 #[test]
759 fn test_value_serialization_roundtrip() {
760 let values = vec![
761 Value::Null,
762 Value::Bool(true),
763 Value::Int64(i64::MAX),
764 Value::Float64(std::f64::consts::PI),
765 Value::String("hello world".into()),
766 Value::Bytes(vec![0, 1, 2, 255].into()),
767 Value::List(vec![Value::Int64(1), Value::Int64(2)].into()),
768 ];
769
770 for v in values {
771 let bytes = v.serialize();
772 let decoded = Value::deserialize(&bytes).unwrap();
773 assert_eq!(v, decoded);
774 }
775 }
776
777 #[test]
778 fn test_property_key() {
779 let key = PropertyKey::new("name");
780 assert_eq!(key.as_str(), "name");
781
782 let key2: PropertyKey = "age".into();
783 assert_eq!(key2.as_str(), "age");
784
785 assert!(key2 < key);
787 }
788
789 #[test]
790 fn test_value_type_name() {
791 assert_eq!(Value::Null.type_name(), "NULL");
792 assert_eq!(Value::Bool(true).type_name(), "BOOL");
793 assert_eq!(Value::Int64(0).type_name(), "INT64");
794 assert_eq!(Value::Float64(0.0).type_name(), "FLOAT64");
795 assert_eq!(Value::String("".into()).type_name(), "STRING");
796 assert_eq!(Value::Bytes(vec![].into()).type_name(), "BYTES");
797 assert_eq!(Value::List(vec![].into()).type_name(), "LIST");
798 assert_eq!(Value::Map(BTreeMap::new().into()).type_name(), "MAP");
799 }
800
801 #[test]
802 fn test_hashable_value_basic() {
803 use std::collections::HashMap;
804
805 let mut map: HashMap<HashableValue, i32> = HashMap::new();
806
807 map.insert(HashableValue::new(Value::Int64(42)), 1);
809 map.insert(HashableValue::new(Value::String("test".into())), 2);
810 map.insert(HashableValue::new(Value::Bool(true)), 3);
811 map.insert(HashableValue::new(Value::Float64(3.14)), 4);
812
813 assert_eq!(map.get(&HashableValue::new(Value::Int64(42))), Some(&1));
814 assert_eq!(
815 map.get(&HashableValue::new(Value::String("test".into()))),
816 Some(&2)
817 );
818 assert_eq!(map.get(&HashableValue::new(Value::Bool(true))), Some(&3));
819 assert_eq!(map.get(&HashableValue::new(Value::Float64(3.14))), Some(&4));
820 }
821
822 #[test]
823 fn test_hashable_value_float_edge_cases() {
824 use std::collections::HashMap;
825
826 let mut map: HashMap<HashableValue, i32> = HashMap::new();
827
828 let nan = f64::NAN;
830 map.insert(HashableValue::new(Value::Float64(nan)), 1);
831 assert_eq!(map.get(&HashableValue::new(Value::Float64(nan))), Some(&1));
832
833 let pos_zero = 0.0f64;
835 let neg_zero = -0.0f64;
836 map.insert(HashableValue::new(Value::Float64(pos_zero)), 2);
837 map.insert(HashableValue::new(Value::Float64(neg_zero)), 3);
838 assert_eq!(
839 map.get(&HashableValue::new(Value::Float64(pos_zero))),
840 Some(&2)
841 );
842 assert_eq!(
843 map.get(&HashableValue::new(Value::Float64(neg_zero))),
844 Some(&3)
845 );
846 }
847
848 #[test]
849 fn test_hashable_value_equality() {
850 let v1 = HashableValue::new(Value::Int64(42));
851 let v2 = HashableValue::new(Value::Int64(42));
852 let v3 = HashableValue::new(Value::Int64(43));
853
854 assert_eq!(v1, v2);
855 assert_ne!(v1, v3);
856 }
857
858 #[test]
859 fn test_hashable_value_inner() {
860 let hv = HashableValue::new(Value::String("hello".into()));
861 assert_eq!(hv.inner().as_str(), Some("hello"));
862
863 let v = hv.into_inner();
864 assert_eq!(v.as_str(), Some("hello"));
865 }
866
867 #[test]
868 fn test_hashable_value_conversions() {
869 let v = Value::Int64(42);
870 let hv: HashableValue = v.clone().into();
871 let v2: Value = hv.into();
872 assert_eq!(v, v2);
873 }
874
875 #[test]
876 fn test_orderable_value_try_from() {
877 assert!(OrderableValue::try_from(&Value::Int64(42)).is_some());
879 assert!(OrderableValue::try_from(&Value::Float64(3.14)).is_some());
880 assert!(OrderableValue::try_from(&Value::String("test".into())).is_some());
881 assert!(OrderableValue::try_from(&Value::Bool(true)).is_some());
882 assert!(OrderableValue::try_from(&Value::Timestamp(Timestamp::from_secs(1000))).is_some());
883
884 assert!(OrderableValue::try_from(&Value::Null).is_none());
886 assert!(OrderableValue::try_from(&Value::Bytes(vec![1, 2, 3].into())).is_none());
887 assert!(OrderableValue::try_from(&Value::List(vec![].into())).is_none());
888 assert!(OrderableValue::try_from(&Value::Map(BTreeMap::new().into())).is_none());
889 }
890
891 #[test]
892 fn test_orderable_value_ordering() {
893 use std::collections::BTreeSet;
894
895 let mut set = BTreeSet::new();
897 set.insert(OrderableValue::try_from(&Value::Int64(30)).unwrap());
898 set.insert(OrderableValue::try_from(&Value::Int64(10)).unwrap());
899 set.insert(OrderableValue::try_from(&Value::Int64(20)).unwrap());
900
901 let values: Vec<_> = set.iter().filter_map(|v| v.as_i64()).collect();
902 assert_eq!(values, vec![10, 20, 30]);
903 }
904
905 #[test]
906 fn test_orderable_value_float_ordering() {
907 let v1 = OrderableValue::try_from(&Value::Float64(1.0)).unwrap();
908 let v2 = OrderableValue::try_from(&Value::Float64(2.0)).unwrap();
909 let v_nan = OrderableValue::try_from(&Value::Float64(f64::NAN)).unwrap();
910 let v_inf = OrderableValue::try_from(&Value::Float64(f64::INFINITY)).unwrap();
911
912 assert!(v1 < v2);
913 assert!(v2 < v_inf);
914 assert!(v_inf < v_nan); assert!(v_nan == v_nan); }
917
918 #[test]
919 fn test_orderable_value_string_ordering() {
920 let a = OrderableValue::try_from(&Value::String("apple".into())).unwrap();
921 let b = OrderableValue::try_from(&Value::String("banana".into())).unwrap();
922 let c = OrderableValue::try_from(&Value::String("cherry".into())).unwrap();
923
924 assert!(a < b);
925 assert!(b < c);
926 }
927
928 #[test]
929 fn test_orderable_value_into_value() {
930 let original = Value::Int64(42);
931 let orderable = OrderableValue::try_from(&original).unwrap();
932 let back = orderable.into_value();
933 assert_eq!(original, back);
934
935 let original = Value::Float64(3.14);
936 let orderable = OrderableValue::try_from(&original).unwrap();
937 let back = orderable.into_value();
938 assert_eq!(original, back);
939
940 let original = Value::String("test".into());
941 let orderable = OrderableValue::try_from(&original).unwrap();
942 let back = orderable.into_value();
943 assert_eq!(original, back);
944 }
945
946 #[test]
947 fn test_orderable_value_cross_type_numeric() {
948 let i = OrderableValue::try_from(&Value::Int64(10)).unwrap();
950 let f = OrderableValue::try_from(&Value::Float64(10.0)).unwrap();
951
952 assert_eq!(i, f);
954
955 let f2 = OrderableValue::try_from(&Value::Float64(10.5)).unwrap();
956 assert!(i < f2);
957 }
958
959 #[test]
960 fn test_ordered_float64_nan_handling() {
961 let nan1 = OrderedFloat64::new(f64::NAN);
962 let nan2 = OrderedFloat64::new(f64::NAN);
963 let inf = OrderedFloat64::new(f64::INFINITY);
964 let neg_inf = OrderedFloat64::new(f64::NEG_INFINITY);
965 let zero = OrderedFloat64::new(0.0);
966
967 assert_eq!(nan1, nan2);
969
970 assert!(neg_inf < zero);
972 assert!(zero < inf);
973 assert!(inf < nan1);
974 }
975}