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 Vector(Arc<[f32]>),
120}
121
122impl Value {
123 #[inline]
125 #[must_use]
126 pub const fn is_null(&self) -> bool {
127 matches!(self, Value::Null)
128 }
129
130 #[inline]
132 #[must_use]
133 pub const fn as_bool(&self) -> Option<bool> {
134 match self {
135 Value::Bool(b) => Some(*b),
136 _ => None,
137 }
138 }
139
140 #[inline]
142 #[must_use]
143 pub const fn as_int64(&self) -> Option<i64> {
144 match self {
145 Value::Int64(i) => Some(*i),
146 _ => None,
147 }
148 }
149
150 #[inline]
152 #[must_use]
153 pub const fn as_float64(&self) -> Option<f64> {
154 match self {
155 Value::Float64(f) => Some(*f),
156 _ => None,
157 }
158 }
159
160 #[inline]
162 #[must_use]
163 pub fn as_str(&self) -> Option<&str> {
164 match self {
165 Value::String(s) => Some(s),
166 _ => None,
167 }
168 }
169
170 #[inline]
172 #[must_use]
173 pub fn as_bytes(&self) -> Option<&[u8]> {
174 match self {
175 Value::Bytes(b) => Some(b),
176 _ => None,
177 }
178 }
179
180 #[inline]
182 #[must_use]
183 pub const fn as_timestamp(&self) -> Option<Timestamp> {
184 match self {
185 Value::Timestamp(t) => Some(*t),
186 _ => None,
187 }
188 }
189
190 #[inline]
192 #[must_use]
193 pub fn as_list(&self) -> Option<&[Value]> {
194 match self {
195 Value::List(l) => Some(l),
196 _ => None,
197 }
198 }
199
200 #[inline]
202 #[must_use]
203 pub fn as_map(&self) -> Option<&BTreeMap<PropertyKey, Value>> {
204 match self {
205 Value::Map(m) => Some(m),
206 _ => None,
207 }
208 }
209
210 #[inline]
212 #[must_use]
213 pub fn as_vector(&self) -> Option<&[f32]> {
214 match self {
215 Value::Vector(v) => Some(v),
216 _ => None,
217 }
218 }
219
220 #[inline]
222 #[must_use]
223 pub const fn is_vector(&self) -> bool {
224 matches!(self, Value::Vector(_))
225 }
226
227 #[inline]
229 #[must_use]
230 pub fn vector_dimensions(&self) -> Option<usize> {
231 match self {
232 Value::Vector(v) => Some(v.len()),
233 _ => None,
234 }
235 }
236
237 #[must_use]
239 pub const fn type_name(&self) -> &'static str {
240 match self {
241 Value::Null => "NULL",
242 Value::Bool(_) => "BOOL",
243 Value::Int64(_) => "INT64",
244 Value::Float64(_) => "FLOAT64",
245 Value::String(_) => "STRING",
246 Value::Bytes(_) => "BYTES",
247 Value::Timestamp(_) => "TIMESTAMP",
248 Value::List(_) => "LIST",
249 Value::Map(_) => "MAP",
250 Value::Vector(_) => "VECTOR",
251 }
252 }
253
254 #[must_use]
256 pub fn serialize(&self) -> Vec<u8> {
257 bincode::serde::encode_to_vec(self, bincode::config::standard())
258 .expect("Value serialization should not fail")
259 }
260
261 pub fn deserialize(bytes: &[u8]) -> Result<Self, bincode::error::DecodeError> {
267 let (value, _) = bincode::serde::decode_from_slice(bytes, bincode::config::standard())?;
268 Ok(value)
269 }
270}
271
272impl fmt::Debug for Value {
273 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
274 match self {
275 Value::Null => write!(f, "Null"),
276 Value::Bool(b) => write!(f, "Bool({b})"),
277 Value::Int64(i) => write!(f, "Int64({i})"),
278 Value::Float64(fl) => write!(f, "Float64({fl})"),
279 Value::String(s) => write!(f, "String({s:?})"),
280 Value::Bytes(b) => write!(f, "Bytes([{}; {} bytes])", b.first().unwrap_or(&0), b.len()),
281 Value::Timestamp(t) => write!(f, "Timestamp({t:?})"),
282 Value::List(l) => write!(f, "List({l:?})"),
283 Value::Map(m) => write!(f, "Map({m:?})"),
284 Value::Vector(v) => write!(
285 f,
286 "Vector([{}; {} dims])",
287 v.first().unwrap_or(&0.0),
288 v.len()
289 ),
290 }
291 }
292}
293
294impl fmt::Display for Value {
295 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
296 match self {
297 Value::Null => write!(f, "NULL"),
298 Value::Bool(b) => write!(f, "{b}"),
299 Value::Int64(i) => write!(f, "{i}"),
300 Value::Float64(fl) => write!(f, "{fl}"),
301 Value::String(s) => write!(f, "{s:?}"),
302 Value::Bytes(b) => write!(f, "<bytes: {} bytes>", b.len()),
303 Value::Timestamp(t) => write!(f, "{t}"),
304 Value::List(l) => {
305 write!(f, "[")?;
306 for (i, v) in l.iter().enumerate() {
307 if i > 0 {
308 write!(f, ", ")?;
309 }
310 write!(f, "{v}")?;
311 }
312 write!(f, "]")
313 }
314 Value::Map(m) => {
315 write!(f, "{{")?;
316 for (i, (k, v)) in m.iter().enumerate() {
317 if i > 0 {
318 write!(f, ", ")?;
319 }
320 write!(f, "{k}: {v}")?;
321 }
322 write!(f, "}}")
323 }
324 Value::Vector(v) => {
325 write!(f, "vector([")?;
326 let show_count = v.len().min(3);
327 for (i, val) in v.iter().take(show_count).enumerate() {
328 if i > 0 {
329 write!(f, ", ")?;
330 }
331 write!(f, "{val}")?;
332 }
333 if v.len() > 3 {
334 write!(f, ", ... ({} dims)", v.len())?;
335 }
336 write!(f, "])")
337 }
338 }
339 }
340}
341
342impl From<bool> for Value {
344 fn from(b: bool) -> Self {
345 Value::Bool(b)
346 }
347}
348
349impl From<i64> for Value {
350 fn from(i: i64) -> Self {
351 Value::Int64(i)
352 }
353}
354
355impl From<i32> for Value {
356 fn from(i: i32) -> Self {
357 Value::Int64(i64::from(i))
358 }
359}
360
361impl From<f64> for Value {
362 fn from(f: f64) -> Self {
363 Value::Float64(f)
364 }
365}
366
367impl From<f32> for Value {
368 fn from(f: f32) -> Self {
369 Value::Float64(f64::from(f))
370 }
371}
372
373impl From<&str> for Value {
374 fn from(s: &str) -> Self {
375 Value::String(s.into())
376 }
377}
378
379impl From<String> for Value {
380 fn from(s: String) -> Self {
381 Value::String(s.into())
382 }
383}
384
385impl From<ArcStr> for Value {
386 fn from(s: ArcStr) -> Self {
387 Value::String(s)
388 }
389}
390
391impl From<Vec<u8>> for Value {
392 fn from(b: Vec<u8>) -> Self {
393 Value::Bytes(b.into())
394 }
395}
396
397impl From<&[u8]> for Value {
398 fn from(b: &[u8]) -> Self {
399 Value::Bytes(b.into())
400 }
401}
402
403impl From<Timestamp> for Value {
404 fn from(t: Timestamp) -> Self {
405 Value::Timestamp(t)
406 }
407}
408
409impl<T: Into<Value>> From<Vec<T>> for Value {
410 fn from(v: Vec<T>) -> Self {
411 Value::List(v.into_iter().map(Into::into).collect())
412 }
413}
414
415impl From<&[f32]> for Value {
416 fn from(v: &[f32]) -> Self {
417 Value::Vector(v.into())
418 }
419}
420
421impl From<Arc<[f32]>> for Value {
422 fn from(v: Arc<[f32]>) -> Self {
423 Value::Vector(v)
424 }
425}
426
427impl<T: Into<Value>> From<Option<T>> for Value {
428 fn from(opt: Option<T>) -> Self {
429 match opt {
430 Some(v) => v.into(),
431 None => Value::Null,
432 }
433 }
434}
435
436#[derive(Clone, Debug)]
448pub struct HashableValue(pub Value);
449
450#[derive(Clone, Debug)]
482pub enum OrderableValue {
483 Int64(i64),
485 Float64(OrderedFloat64),
487 String(ArcStr),
489 Bool(bool),
491 Timestamp(Timestamp),
493}
494
495#[derive(Clone, Copy, Debug)]
500pub struct OrderedFloat64(pub f64);
501
502impl OrderedFloat64 {
503 #[must_use]
505 pub const fn new(f: f64) -> Self {
506 Self(f)
507 }
508
509 #[must_use]
511 pub const fn get(&self) -> f64 {
512 self.0
513 }
514}
515
516impl PartialEq for OrderedFloat64 {
517 fn eq(&self, other: &Self) -> bool {
518 match (self.0.is_nan(), other.0.is_nan()) {
520 (true, true) => true,
521 (true, false) | (false, true) => false,
522 (false, false) => self.0 == other.0,
523 }
524 }
525}
526
527impl Eq for OrderedFloat64 {}
528
529impl PartialOrd for OrderedFloat64 {
530 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
531 Some(self.cmp(other))
532 }
533}
534
535impl Ord for OrderedFloat64 {
536 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
537 match (self.0.is_nan(), other.0.is_nan()) {
539 (true, true) => std::cmp::Ordering::Equal,
540 (true, false) => std::cmp::Ordering::Greater,
541 (false, true) => std::cmp::Ordering::Less,
542 (false, false) => {
543 self.0
545 .partial_cmp(&other.0)
546 .unwrap_or(std::cmp::Ordering::Equal)
547 }
548 }
549 }
550}
551
552impl Hash for OrderedFloat64 {
553 fn hash<H: Hasher>(&self, state: &mut H) {
554 self.0.to_bits().hash(state);
555 }
556}
557
558impl From<f64> for OrderedFloat64 {
559 fn from(f: f64) -> Self {
560 Self(f)
561 }
562}
563
564impl OrderableValue {
565 #[must_use]
570 pub fn try_from(value: &Value) -> Option<Self> {
571 match value {
572 Value::Int64(i) => Some(Self::Int64(*i)),
573 Value::Float64(f) => Some(Self::Float64(OrderedFloat64(*f))),
574 Value::String(s) => Some(Self::String(s.clone())),
575 Value::Bool(b) => Some(Self::Bool(*b)),
576 Value::Timestamp(t) => Some(Self::Timestamp(*t)),
577 Value::Null | Value::Bytes(_) | Value::List(_) | Value::Map(_) | Value::Vector(_) => {
578 None
579 }
580 }
581 }
582
583 #[must_use]
585 pub fn into_value(self) -> Value {
586 match self {
587 Self::Int64(i) => Value::Int64(i),
588 Self::Float64(f) => Value::Float64(f.0),
589 Self::String(s) => Value::String(s),
590 Self::Bool(b) => Value::Bool(b),
591 Self::Timestamp(t) => Value::Timestamp(t),
592 }
593 }
594
595 #[must_use]
597 pub const fn as_i64(&self) -> Option<i64> {
598 match self {
599 Self::Int64(i) => Some(*i),
600 _ => None,
601 }
602 }
603
604 #[must_use]
606 pub const fn as_f64(&self) -> Option<f64> {
607 match self {
608 Self::Float64(f) => Some(f.0),
609 _ => None,
610 }
611 }
612
613 #[must_use]
615 pub fn as_str(&self) -> Option<&str> {
616 match self {
617 Self::String(s) => Some(s),
618 _ => None,
619 }
620 }
621}
622
623impl PartialEq for OrderableValue {
624 fn eq(&self, other: &Self) -> bool {
625 match (self, other) {
626 (Self::Int64(a), Self::Int64(b)) => a == b,
627 (Self::Float64(a), Self::Float64(b)) => a == b,
628 (Self::String(a), Self::String(b)) => a == b,
629 (Self::Bool(a), Self::Bool(b)) => a == b,
630 (Self::Timestamp(a), Self::Timestamp(b)) => a == b,
631 (Self::Int64(a), Self::Float64(b)) => (*a as f64) == b.0,
633 (Self::Float64(a), Self::Int64(b)) => a.0 == (*b as f64),
634 _ => false,
635 }
636 }
637}
638
639impl Eq for OrderableValue {}
640
641impl PartialOrd for OrderableValue {
642 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
643 Some(self.cmp(other))
644 }
645}
646
647impl Ord for OrderableValue {
648 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
649 match (self, other) {
650 (Self::Int64(a), Self::Int64(b)) => a.cmp(b),
651 (Self::Float64(a), Self::Float64(b)) => a.cmp(b),
652 (Self::String(a), Self::String(b)) => a.cmp(b),
653 (Self::Bool(a), Self::Bool(b)) => a.cmp(b),
654 (Self::Timestamp(a), Self::Timestamp(b)) => a.cmp(b),
655 (Self::Int64(a), Self::Float64(b)) => OrderedFloat64(*a as f64).cmp(b),
657 (Self::Float64(a), Self::Int64(b)) => a.cmp(&OrderedFloat64(*b as f64)),
658 _ => self.type_ordinal().cmp(&other.type_ordinal()),
661 }
662 }
663}
664
665impl OrderableValue {
666 const fn type_ordinal(&self) -> u8 {
668 match self {
669 Self::Bool(_) => 0,
670 Self::Int64(_) => 1,
671 Self::Float64(_) => 2,
672 Self::String(_) => 3,
673 Self::Timestamp(_) => 4,
674 }
675 }
676}
677
678impl Hash for OrderableValue {
679 fn hash<H: Hasher>(&self, state: &mut H) {
680 std::mem::discriminant(self).hash(state);
681 match self {
682 Self::Int64(i) => i.hash(state),
683 Self::Float64(f) => f.hash(state),
684 Self::String(s) => s.hash(state),
685 Self::Bool(b) => b.hash(state),
686 Self::Timestamp(t) => t.hash(state),
687 }
688 }
689}
690
691impl HashableValue {
692 #[must_use]
694 pub fn new(value: Value) -> Self {
695 Self(value)
696 }
697
698 #[must_use]
700 pub fn inner(&self) -> &Value {
701 &self.0
702 }
703
704 #[must_use]
706 pub fn into_inner(self) -> Value {
707 self.0
708 }
709}
710
711impl Hash for HashableValue {
712 fn hash<H: Hasher>(&self, state: &mut H) {
713 std::mem::discriminant(&self.0).hash(state);
715
716 match &self.0 {
717 Value::Null => {}
718 Value::Bool(b) => b.hash(state),
719 Value::Int64(i) => i.hash(state),
720 Value::Float64(f) => {
721 f.to_bits().hash(state);
723 }
724 Value::String(s) => s.hash(state),
725 Value::Bytes(b) => b.hash(state),
726 Value::Timestamp(t) => t.hash(state),
727 Value::List(l) => {
728 l.len().hash(state);
729 for v in l.iter() {
730 HashableValue(v.clone()).hash(state);
731 }
732 }
733 Value::Map(m) => {
734 m.len().hash(state);
735 for (k, v) in m.iter() {
736 k.hash(state);
737 HashableValue(v.clone()).hash(state);
738 }
739 }
740 Value::Vector(v) => {
741 v.len().hash(state);
742 for &f in v.iter() {
743 f.to_bits().hash(state);
744 }
745 }
746 }
747 }
748}
749
750impl PartialEq for HashableValue {
751 fn eq(&self, other: &Self) -> bool {
752 match (&self.0, &other.0) {
753 (Value::Float64(a), Value::Float64(b)) => {
754 a.to_bits() == b.to_bits()
756 }
757 (Value::List(a), Value::List(b)) => {
758 if a.len() != b.len() {
759 return false;
760 }
761 a.iter()
762 .zip(b.iter())
763 .all(|(x, y)| HashableValue(x.clone()) == HashableValue(y.clone()))
764 }
765 (Value::Map(a), Value::Map(b)) => {
766 if a.len() != b.len() {
767 return false;
768 }
769 a.iter().all(|(k, v)| {
770 b.get(k)
771 .is_some_and(|bv| HashableValue(v.clone()) == HashableValue(bv.clone()))
772 })
773 }
774 (Value::Vector(a), Value::Vector(b)) => {
775 if a.len() != b.len() {
776 return false;
777 }
778 a.iter()
780 .zip(b.iter())
781 .all(|(x, y)| x.to_bits() == y.to_bits())
782 }
783 _ => self.0 == other.0,
785 }
786 }
787}
788
789impl Eq for HashableValue {}
790
791impl From<Value> for HashableValue {
792 fn from(value: Value) -> Self {
793 Self(value)
794 }
795}
796
797impl From<HashableValue> for Value {
798 fn from(hv: HashableValue) -> Self {
799 hv.0
800 }
801}
802
803#[cfg(test)]
804mod tests {
805 use super::*;
806
807 #[test]
808 fn test_value_type_checks() {
809 assert!(Value::Null.is_null());
810 assert!(!Value::Bool(true).is_null());
811
812 assert_eq!(Value::Bool(true).as_bool(), Some(true));
813 assert_eq!(Value::Bool(false).as_bool(), Some(false));
814 assert_eq!(Value::Int64(42).as_bool(), None);
815
816 assert_eq!(Value::Int64(42).as_int64(), Some(42));
817 assert_eq!(Value::String("test".into()).as_int64(), None);
818
819 assert_eq!(Value::Float64(1.234).as_float64(), Some(1.234));
820 assert_eq!(Value::String("hello".into()).as_str(), Some("hello"));
821 }
822
823 #[test]
824 fn test_value_from_conversions() {
825 let v: Value = true.into();
826 assert_eq!(v.as_bool(), Some(true));
827
828 let v: Value = 42i64.into();
829 assert_eq!(v.as_int64(), Some(42));
830
831 let v: Value = 1.234f64.into();
832 assert_eq!(v.as_float64(), Some(1.234));
833
834 let v: Value = "hello".into();
835 assert_eq!(v.as_str(), Some("hello"));
836
837 let v: Value = vec![1u8, 2, 3].into();
838 assert_eq!(v.as_bytes(), Some(&[1u8, 2, 3][..]));
839 }
840
841 #[test]
842 fn test_value_serialization_roundtrip() {
843 let values = vec![
844 Value::Null,
845 Value::Bool(true),
846 Value::Int64(i64::MAX),
847 Value::Float64(std::f64::consts::PI),
848 Value::String("hello world".into()),
849 Value::Bytes(vec![0, 1, 2, 255].into()),
850 Value::List(vec![Value::Int64(1), Value::Int64(2)].into()),
851 ];
852
853 for v in values {
854 let bytes = v.serialize();
855 let decoded = Value::deserialize(&bytes).unwrap();
856 assert_eq!(v, decoded);
857 }
858 }
859
860 #[test]
861 fn test_property_key() {
862 let key = PropertyKey::new("name");
863 assert_eq!(key.as_str(), "name");
864
865 let key2: PropertyKey = "age".into();
866 assert_eq!(key2.as_str(), "age");
867
868 assert!(key2 < key);
870 }
871
872 #[test]
873 fn test_value_type_name() {
874 assert_eq!(Value::Null.type_name(), "NULL");
875 assert_eq!(Value::Bool(true).type_name(), "BOOL");
876 assert_eq!(Value::Int64(0).type_name(), "INT64");
877 assert_eq!(Value::Float64(0.0).type_name(), "FLOAT64");
878 assert_eq!(Value::String("".into()).type_name(), "STRING");
879 assert_eq!(Value::Bytes(vec![].into()).type_name(), "BYTES");
880 assert_eq!(Value::List(vec![].into()).type_name(), "LIST");
881 assert_eq!(Value::Map(BTreeMap::new().into()).type_name(), "MAP");
882 assert_eq!(Value::Vector(vec![].into()).type_name(), "VECTOR");
883 }
884
885 #[test]
886 fn test_value_vector() {
887 let v = Value::Vector(vec![0.1f32, 0.2, 0.3].into());
889 assert!(v.is_vector());
890 assert_eq!(v.vector_dimensions(), Some(3));
891 assert_eq!(v.as_vector(), Some(&[0.1f32, 0.2, 0.3][..]));
892
893 let slice: &[f32] = &[1.0, 2.0, 3.0, 4.0];
895 let v2: Value = slice.into();
896 assert!(v2.is_vector());
897 assert_eq!(v2.vector_dimensions(), Some(4));
898
899 let arc: Arc<[f32]> = vec![5.0f32, 6.0].into();
901 let v3: Value = arc.into();
902 assert!(v3.is_vector());
903 assert_eq!(v3.vector_dimensions(), Some(2));
904
905 assert!(!Value::Int64(42).is_vector());
907 assert_eq!(Value::Int64(42).as_vector(), None);
908 assert_eq!(Value::Int64(42).vector_dimensions(), None);
909 }
910
911 #[test]
912 fn test_hashable_value_vector() {
913 use std::collections::HashMap;
914
915 let mut map: HashMap<HashableValue, i32> = HashMap::new();
916
917 let v1 = HashableValue::new(Value::Vector(vec![0.1f32, 0.2, 0.3].into()));
918 let v2 = HashableValue::new(Value::Vector(vec![0.1f32, 0.2, 0.3].into()));
919 let v3 = HashableValue::new(Value::Vector(vec![0.4f32, 0.5, 0.6].into()));
920
921 map.insert(v1.clone(), 1);
922
923 assert_eq!(map.get(&v2), Some(&1));
925
926 assert_eq!(map.get(&v3), None);
928
929 assert_eq!(v1, v2);
931 assert_ne!(v1, v3);
932 }
933
934 #[test]
935 fn test_orderable_value_vector_unsupported() {
936 let v = Value::Vector(vec![0.1f32, 0.2, 0.3].into());
938 assert!(OrderableValue::try_from(&v).is_none());
939 }
940
941 #[test]
942 fn test_hashable_value_basic() {
943 use std::collections::HashMap;
944
945 let mut map: HashMap<HashableValue, i32> = HashMap::new();
946
947 map.insert(HashableValue::new(Value::Int64(42)), 1);
949 map.insert(HashableValue::new(Value::String("test".into())), 2);
950 map.insert(HashableValue::new(Value::Bool(true)), 3);
951 map.insert(HashableValue::new(Value::Float64(3.14)), 4);
952
953 assert_eq!(map.get(&HashableValue::new(Value::Int64(42))), Some(&1));
954 assert_eq!(
955 map.get(&HashableValue::new(Value::String("test".into()))),
956 Some(&2)
957 );
958 assert_eq!(map.get(&HashableValue::new(Value::Bool(true))), Some(&3));
959 assert_eq!(map.get(&HashableValue::new(Value::Float64(3.14))), Some(&4));
960 }
961
962 #[test]
963 fn test_hashable_value_float_edge_cases() {
964 use std::collections::HashMap;
965
966 let mut map: HashMap<HashableValue, i32> = HashMap::new();
967
968 let nan = f64::NAN;
970 map.insert(HashableValue::new(Value::Float64(nan)), 1);
971 assert_eq!(map.get(&HashableValue::new(Value::Float64(nan))), Some(&1));
972
973 let pos_zero = 0.0f64;
975 let neg_zero = -0.0f64;
976 map.insert(HashableValue::new(Value::Float64(pos_zero)), 2);
977 map.insert(HashableValue::new(Value::Float64(neg_zero)), 3);
978 assert_eq!(
979 map.get(&HashableValue::new(Value::Float64(pos_zero))),
980 Some(&2)
981 );
982 assert_eq!(
983 map.get(&HashableValue::new(Value::Float64(neg_zero))),
984 Some(&3)
985 );
986 }
987
988 #[test]
989 fn test_hashable_value_equality() {
990 let v1 = HashableValue::new(Value::Int64(42));
991 let v2 = HashableValue::new(Value::Int64(42));
992 let v3 = HashableValue::new(Value::Int64(43));
993
994 assert_eq!(v1, v2);
995 assert_ne!(v1, v3);
996 }
997
998 #[test]
999 fn test_hashable_value_inner() {
1000 let hv = HashableValue::new(Value::String("hello".into()));
1001 assert_eq!(hv.inner().as_str(), Some("hello"));
1002
1003 let v = hv.into_inner();
1004 assert_eq!(v.as_str(), Some("hello"));
1005 }
1006
1007 #[test]
1008 fn test_hashable_value_conversions() {
1009 let v = Value::Int64(42);
1010 let hv: HashableValue = v.clone().into();
1011 let v2: Value = hv.into();
1012 assert_eq!(v, v2);
1013 }
1014
1015 #[test]
1016 fn test_orderable_value_try_from() {
1017 assert!(OrderableValue::try_from(&Value::Int64(42)).is_some());
1019 assert!(OrderableValue::try_from(&Value::Float64(3.14)).is_some());
1020 assert!(OrderableValue::try_from(&Value::String("test".into())).is_some());
1021 assert!(OrderableValue::try_from(&Value::Bool(true)).is_some());
1022 assert!(OrderableValue::try_from(&Value::Timestamp(Timestamp::from_secs(1000))).is_some());
1023
1024 assert!(OrderableValue::try_from(&Value::Null).is_none());
1026 assert!(OrderableValue::try_from(&Value::Bytes(vec![1, 2, 3].into())).is_none());
1027 assert!(OrderableValue::try_from(&Value::List(vec![].into())).is_none());
1028 assert!(OrderableValue::try_from(&Value::Map(BTreeMap::new().into())).is_none());
1029 }
1030
1031 #[test]
1032 fn test_orderable_value_ordering() {
1033 use std::collections::BTreeSet;
1034
1035 let mut set = BTreeSet::new();
1037 set.insert(OrderableValue::try_from(&Value::Int64(30)).unwrap());
1038 set.insert(OrderableValue::try_from(&Value::Int64(10)).unwrap());
1039 set.insert(OrderableValue::try_from(&Value::Int64(20)).unwrap());
1040
1041 let values: Vec<_> = set.iter().filter_map(|v| v.as_i64()).collect();
1042 assert_eq!(values, vec![10, 20, 30]);
1043 }
1044
1045 #[test]
1046 fn test_orderable_value_float_ordering() {
1047 let v1 = OrderableValue::try_from(&Value::Float64(1.0)).unwrap();
1048 let v2 = OrderableValue::try_from(&Value::Float64(2.0)).unwrap();
1049 let v_nan = OrderableValue::try_from(&Value::Float64(f64::NAN)).unwrap();
1050 let v_inf = OrderableValue::try_from(&Value::Float64(f64::INFINITY)).unwrap();
1051
1052 assert!(v1 < v2);
1053 assert!(v2 < v_inf);
1054 assert!(v_inf < v_nan); assert!(v_nan == v_nan); }
1057
1058 #[test]
1059 fn test_orderable_value_string_ordering() {
1060 let a = OrderableValue::try_from(&Value::String("apple".into())).unwrap();
1061 let b = OrderableValue::try_from(&Value::String("banana".into())).unwrap();
1062 let c = OrderableValue::try_from(&Value::String("cherry".into())).unwrap();
1063
1064 assert!(a < b);
1065 assert!(b < c);
1066 }
1067
1068 #[test]
1069 fn test_orderable_value_into_value() {
1070 let original = Value::Int64(42);
1071 let orderable = OrderableValue::try_from(&original).unwrap();
1072 let back = orderable.into_value();
1073 assert_eq!(original, back);
1074
1075 let original = Value::Float64(3.14);
1076 let orderable = OrderableValue::try_from(&original).unwrap();
1077 let back = orderable.into_value();
1078 assert_eq!(original, back);
1079
1080 let original = Value::String("test".into());
1081 let orderable = OrderableValue::try_from(&original).unwrap();
1082 let back = orderable.into_value();
1083 assert_eq!(original, back);
1084 }
1085
1086 #[test]
1087 fn test_orderable_value_cross_type_numeric() {
1088 let i = OrderableValue::try_from(&Value::Int64(10)).unwrap();
1090 let f = OrderableValue::try_from(&Value::Float64(10.0)).unwrap();
1091
1092 assert_eq!(i, f);
1094
1095 let f2 = OrderableValue::try_from(&Value::Float64(10.5)).unwrap();
1096 assert!(i < f2);
1097 }
1098
1099 #[test]
1100 fn test_ordered_float64_nan_handling() {
1101 let nan1 = OrderedFloat64::new(f64::NAN);
1102 let nan2 = OrderedFloat64::new(f64::NAN);
1103 let inf = OrderedFloat64::new(f64::INFINITY);
1104 let neg_inf = OrderedFloat64::new(f64::NEG_INFINITY);
1105 let zero = OrderedFloat64::new(0.0);
1106
1107 assert_eq!(nan1, nan2);
1109
1110 assert!(neg_inf < zero);
1112 assert!(zero < inf);
1113 assert!(inf < nan1);
1114 }
1115}