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 pub fn serialize(&self) -> Result<Vec<u8>, bincode::error::EncodeError> {
260 bincode::serde::encode_to_vec(self, bincode::config::standard())
261 }
262
263 pub fn deserialize(bytes: &[u8]) -> Result<Self, bincode::error::DecodeError> {
269 let (value, _) = bincode::serde::decode_from_slice(bytes, bincode::config::standard())?;
270 Ok(value)
271 }
272}
273
274impl fmt::Debug for Value {
275 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
276 match self {
277 Value::Null => write!(f, "Null"),
278 Value::Bool(b) => write!(f, "Bool({b})"),
279 Value::Int64(i) => write!(f, "Int64({i})"),
280 Value::Float64(fl) => write!(f, "Float64({fl})"),
281 Value::String(s) => write!(f, "String({s:?})"),
282 Value::Bytes(b) => write!(f, "Bytes([{}; {} bytes])", b.first().unwrap_or(&0), b.len()),
283 Value::Timestamp(t) => write!(f, "Timestamp({t:?})"),
284 Value::List(l) => write!(f, "List({l:?})"),
285 Value::Map(m) => write!(f, "Map({m:?})"),
286 Value::Vector(v) => write!(
287 f,
288 "Vector([{}; {} dims])",
289 v.first().unwrap_or(&0.0),
290 v.len()
291 ),
292 }
293 }
294}
295
296impl fmt::Display for Value {
297 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
298 match self {
299 Value::Null => write!(f, "NULL"),
300 Value::Bool(b) => write!(f, "{b}"),
301 Value::Int64(i) => write!(f, "{i}"),
302 Value::Float64(fl) => write!(f, "{fl}"),
303 Value::String(s) => write!(f, "{s:?}"),
304 Value::Bytes(b) => write!(f, "<bytes: {} bytes>", b.len()),
305 Value::Timestamp(t) => write!(f, "{t}"),
306 Value::List(l) => {
307 write!(f, "[")?;
308 for (i, v) in l.iter().enumerate() {
309 if i > 0 {
310 write!(f, ", ")?;
311 }
312 write!(f, "{v}")?;
313 }
314 write!(f, "]")
315 }
316 Value::Map(m) => {
317 write!(f, "{{")?;
318 for (i, (k, v)) in m.iter().enumerate() {
319 if i > 0 {
320 write!(f, ", ")?;
321 }
322 write!(f, "{k}: {v}")?;
323 }
324 write!(f, "}}")
325 }
326 Value::Vector(v) => {
327 write!(f, "vector([")?;
328 let show_count = v.len().min(3);
329 for (i, val) in v.iter().take(show_count).enumerate() {
330 if i > 0 {
331 write!(f, ", ")?;
332 }
333 write!(f, "{val}")?;
334 }
335 if v.len() > 3 {
336 write!(f, ", ... ({} dims)", v.len())?;
337 }
338 write!(f, "])")
339 }
340 }
341 }
342}
343
344impl From<bool> for Value {
346 fn from(b: bool) -> Self {
347 Value::Bool(b)
348 }
349}
350
351impl From<i64> for Value {
352 fn from(i: i64) -> Self {
353 Value::Int64(i)
354 }
355}
356
357impl From<i32> for Value {
358 fn from(i: i32) -> Self {
359 Value::Int64(i64::from(i))
360 }
361}
362
363impl From<f64> for Value {
364 fn from(f: f64) -> Self {
365 Value::Float64(f)
366 }
367}
368
369impl From<f32> for Value {
370 fn from(f: f32) -> Self {
371 Value::Float64(f64::from(f))
372 }
373}
374
375impl From<&str> for Value {
376 fn from(s: &str) -> Self {
377 Value::String(s.into())
378 }
379}
380
381impl From<String> for Value {
382 fn from(s: String) -> Self {
383 Value::String(s.into())
384 }
385}
386
387impl From<ArcStr> for Value {
388 fn from(s: ArcStr) -> Self {
389 Value::String(s)
390 }
391}
392
393impl From<Vec<u8>> for Value {
394 fn from(b: Vec<u8>) -> Self {
395 Value::Bytes(b.into())
396 }
397}
398
399impl From<&[u8]> for Value {
400 fn from(b: &[u8]) -> Self {
401 Value::Bytes(b.into())
402 }
403}
404
405impl From<Timestamp> for Value {
406 fn from(t: Timestamp) -> Self {
407 Value::Timestamp(t)
408 }
409}
410
411impl<T: Into<Value>> From<Vec<T>> for Value {
412 fn from(v: Vec<T>) -> Self {
413 Value::List(v.into_iter().map(Into::into).collect())
414 }
415}
416
417impl From<&[f32]> for Value {
418 fn from(v: &[f32]) -> Self {
419 Value::Vector(v.into())
420 }
421}
422
423impl From<Arc<[f32]>> for Value {
424 fn from(v: Arc<[f32]>) -> Self {
425 Value::Vector(v)
426 }
427}
428
429impl<T: Into<Value>> From<Option<T>> for Value {
430 fn from(opt: Option<T>) -> Self {
431 match opt {
432 Some(v) => v.into(),
433 None => Value::Null,
434 }
435 }
436}
437
438#[derive(Clone, Debug)]
450pub struct HashableValue(pub Value);
451
452#[derive(Clone, Debug)]
484pub enum OrderableValue {
485 Int64(i64),
487 Float64(OrderedFloat64),
489 String(ArcStr),
491 Bool(bool),
493 Timestamp(Timestamp),
495}
496
497#[derive(Clone, Copy, Debug)]
502pub struct OrderedFloat64(pub f64);
503
504impl OrderedFloat64 {
505 #[must_use]
507 pub const fn new(f: f64) -> Self {
508 Self(f)
509 }
510
511 #[must_use]
513 pub const fn get(&self) -> f64 {
514 self.0
515 }
516}
517
518impl PartialEq for OrderedFloat64 {
519 fn eq(&self, other: &Self) -> bool {
520 match (self.0.is_nan(), other.0.is_nan()) {
522 (true, true) => true,
523 (true, false) | (false, true) => false,
524 (false, false) => self.0 == other.0,
525 }
526 }
527}
528
529impl Eq for OrderedFloat64 {}
530
531impl PartialOrd for OrderedFloat64 {
532 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
533 Some(self.cmp(other))
534 }
535}
536
537impl Ord for OrderedFloat64 {
538 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
539 match (self.0.is_nan(), other.0.is_nan()) {
541 (true, true) => std::cmp::Ordering::Equal,
542 (true, false) => std::cmp::Ordering::Greater,
543 (false, true) => std::cmp::Ordering::Less,
544 (false, false) => {
545 self.0
547 .partial_cmp(&other.0)
548 .unwrap_or(std::cmp::Ordering::Equal)
549 }
550 }
551 }
552}
553
554impl Hash for OrderedFloat64 {
555 fn hash<H: Hasher>(&self, state: &mut H) {
556 self.0.to_bits().hash(state);
557 }
558}
559
560impl From<f64> for OrderedFloat64 {
561 fn from(f: f64) -> Self {
562 Self(f)
563 }
564}
565
566impl TryFrom<&Value> for OrderableValue {
567 type Error = ();
568
569 fn try_from(value: &Value) -> Result<Self, Self::Error> {
574 match value {
575 Value::Int64(i) => Ok(Self::Int64(*i)),
576 Value::Float64(f) => Ok(Self::Float64(OrderedFloat64(*f))),
577 Value::String(s) => Ok(Self::String(s.clone())),
578 Value::Bool(b) => Ok(Self::Bool(*b)),
579 Value::Timestamp(t) => Ok(Self::Timestamp(*t)),
580 Value::Null | Value::Bytes(_) | Value::List(_) | Value::Map(_) | Value::Vector(_) => {
581 Err(())
582 }
583 }
584 }
585}
586
587impl OrderableValue {
588 #[must_use]
590 pub fn into_value(self) -> Value {
591 match self {
592 Self::Int64(i) => Value::Int64(i),
593 Self::Float64(f) => Value::Float64(f.0),
594 Self::String(s) => Value::String(s),
595 Self::Bool(b) => Value::Bool(b),
596 Self::Timestamp(t) => Value::Timestamp(t),
597 }
598 }
599
600 #[must_use]
602 pub const fn as_i64(&self) -> Option<i64> {
603 match self {
604 Self::Int64(i) => Some(*i),
605 _ => None,
606 }
607 }
608
609 #[must_use]
611 pub const fn as_f64(&self) -> Option<f64> {
612 match self {
613 Self::Float64(f) => Some(f.0),
614 _ => None,
615 }
616 }
617
618 #[must_use]
620 pub fn as_str(&self) -> Option<&str> {
621 match self {
622 Self::String(s) => Some(s),
623 _ => None,
624 }
625 }
626}
627
628impl PartialEq for OrderableValue {
629 fn eq(&self, other: &Self) -> bool {
630 match (self, other) {
631 (Self::Int64(a), Self::Int64(b)) => a == b,
632 (Self::Float64(a), Self::Float64(b)) => a == b,
633 (Self::String(a), Self::String(b)) => a == b,
634 (Self::Bool(a), Self::Bool(b)) => a == b,
635 (Self::Timestamp(a), Self::Timestamp(b)) => a == b,
636 (Self::Int64(a), Self::Float64(b)) => (*a as f64) == b.0,
638 (Self::Float64(a), Self::Int64(b)) => a.0 == (*b as f64),
639 _ => false,
640 }
641 }
642}
643
644impl Eq for OrderableValue {}
645
646impl PartialOrd for OrderableValue {
647 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
648 Some(self.cmp(other))
649 }
650}
651
652impl Ord for OrderableValue {
653 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
654 match (self, other) {
655 (Self::Int64(a), Self::Int64(b)) => a.cmp(b),
656 (Self::Float64(a), Self::Float64(b)) => a.cmp(b),
657 (Self::String(a), Self::String(b)) => a.cmp(b),
658 (Self::Bool(a), Self::Bool(b)) => a.cmp(b),
659 (Self::Timestamp(a), Self::Timestamp(b)) => a.cmp(b),
660 (Self::Int64(a), Self::Float64(b)) => OrderedFloat64(*a as f64).cmp(b),
662 (Self::Float64(a), Self::Int64(b)) => a.cmp(&OrderedFloat64(*b as f64)),
663 _ => self.type_ordinal().cmp(&other.type_ordinal()),
666 }
667 }
668}
669
670impl OrderableValue {
671 const fn type_ordinal(&self) -> u8 {
673 match self {
674 Self::Bool(_) => 0,
675 Self::Int64(_) => 1,
676 Self::Float64(_) => 2,
677 Self::String(_) => 3,
678 Self::Timestamp(_) => 4,
679 }
680 }
681}
682
683impl Hash for OrderableValue {
684 fn hash<H: Hasher>(&self, state: &mut H) {
685 std::mem::discriminant(self).hash(state);
686 match self {
687 Self::Int64(i) => i.hash(state),
688 Self::Float64(f) => f.hash(state),
689 Self::String(s) => s.hash(state),
690 Self::Bool(b) => b.hash(state),
691 Self::Timestamp(t) => t.hash(state),
692 }
693 }
694}
695
696impl HashableValue {
697 #[must_use]
699 pub fn new(value: Value) -> Self {
700 Self(value)
701 }
702
703 #[must_use]
705 pub fn inner(&self) -> &Value {
706 &self.0
707 }
708
709 #[must_use]
711 pub fn into_inner(self) -> Value {
712 self.0
713 }
714}
715
716impl Hash for HashableValue {
717 fn hash<H: Hasher>(&self, state: &mut H) {
718 std::mem::discriminant(&self.0).hash(state);
720
721 match &self.0 {
722 Value::Null => {}
723 Value::Bool(b) => b.hash(state),
724 Value::Int64(i) => i.hash(state),
725 Value::Float64(f) => {
726 f.to_bits().hash(state);
728 }
729 Value::String(s) => s.hash(state),
730 Value::Bytes(b) => b.hash(state),
731 Value::Timestamp(t) => t.hash(state),
732 Value::List(l) => {
733 l.len().hash(state);
734 for v in l.iter() {
735 HashableValue(v.clone()).hash(state);
736 }
737 }
738 Value::Map(m) => {
739 m.len().hash(state);
740 for (k, v) in m.iter() {
741 k.hash(state);
742 HashableValue(v.clone()).hash(state);
743 }
744 }
745 Value::Vector(v) => {
746 v.len().hash(state);
747 for &f in v.iter() {
748 f.to_bits().hash(state);
749 }
750 }
751 }
752 }
753}
754
755impl PartialEq for HashableValue {
756 fn eq(&self, other: &Self) -> bool {
757 match (&self.0, &other.0) {
758 (Value::Float64(a), Value::Float64(b)) => {
759 a.to_bits() == b.to_bits()
761 }
762 (Value::List(a), Value::List(b)) => {
763 if a.len() != b.len() {
764 return false;
765 }
766 a.iter()
767 .zip(b.iter())
768 .all(|(x, y)| HashableValue(x.clone()) == HashableValue(y.clone()))
769 }
770 (Value::Map(a), Value::Map(b)) => {
771 if a.len() != b.len() {
772 return false;
773 }
774 a.iter().all(|(k, v)| {
775 b.get(k)
776 .is_some_and(|bv| HashableValue(v.clone()) == HashableValue(bv.clone()))
777 })
778 }
779 (Value::Vector(a), Value::Vector(b)) => {
780 if a.len() != b.len() {
781 return false;
782 }
783 a.iter()
785 .zip(b.iter())
786 .all(|(x, y)| x.to_bits() == y.to_bits())
787 }
788 _ => self.0 == other.0,
790 }
791 }
792}
793
794impl Eq for HashableValue {}
795
796impl From<Value> for HashableValue {
797 fn from(value: Value) -> Self {
798 Self(value)
799 }
800}
801
802impl From<HashableValue> for Value {
803 fn from(hv: HashableValue) -> Self {
804 hv.0
805 }
806}
807
808#[cfg(test)]
809mod tests {
810 use super::*;
811
812 #[test]
813 fn test_value_type_checks() {
814 assert!(Value::Null.is_null());
815 assert!(!Value::Bool(true).is_null());
816
817 assert_eq!(Value::Bool(true).as_bool(), Some(true));
818 assert_eq!(Value::Bool(false).as_bool(), Some(false));
819 assert_eq!(Value::Int64(42).as_bool(), None);
820
821 assert_eq!(Value::Int64(42).as_int64(), Some(42));
822 assert_eq!(Value::String("test".into()).as_int64(), None);
823
824 assert_eq!(Value::Float64(1.234).as_float64(), Some(1.234));
825 assert_eq!(Value::String("hello".into()).as_str(), Some("hello"));
826 }
827
828 #[test]
829 fn test_value_from_conversions() {
830 let v: Value = true.into();
831 assert_eq!(v.as_bool(), Some(true));
832
833 let v: Value = 42i64.into();
834 assert_eq!(v.as_int64(), Some(42));
835
836 let v: Value = 1.234f64.into();
837 assert_eq!(v.as_float64(), Some(1.234));
838
839 let v: Value = "hello".into();
840 assert_eq!(v.as_str(), Some("hello"));
841
842 let v: Value = vec![1u8, 2, 3].into();
843 assert_eq!(v.as_bytes(), Some(&[1u8, 2, 3][..]));
844 }
845
846 #[test]
847 fn test_value_serialization_roundtrip() {
848 let values = vec![
849 Value::Null,
850 Value::Bool(true),
851 Value::Int64(i64::MAX),
852 Value::Float64(std::f64::consts::PI),
853 Value::String("hello world".into()),
854 Value::Bytes(vec![0, 1, 2, 255].into()),
855 Value::List(vec![Value::Int64(1), Value::Int64(2)].into()),
856 ];
857
858 for v in values {
859 let bytes = v.serialize().unwrap();
860 let decoded = Value::deserialize(&bytes).unwrap();
861 assert_eq!(v, decoded);
862 }
863 }
864
865 #[test]
866 fn test_property_key() {
867 let key = PropertyKey::new("name");
868 assert_eq!(key.as_str(), "name");
869
870 let key2: PropertyKey = "age".into();
871 assert_eq!(key2.as_str(), "age");
872
873 assert!(key2 < key);
875 }
876
877 #[test]
878 fn test_value_type_name() {
879 assert_eq!(Value::Null.type_name(), "NULL");
880 assert_eq!(Value::Bool(true).type_name(), "BOOL");
881 assert_eq!(Value::Int64(0).type_name(), "INT64");
882 assert_eq!(Value::Float64(0.0).type_name(), "FLOAT64");
883 assert_eq!(Value::String("".into()).type_name(), "STRING");
884 assert_eq!(Value::Bytes(vec![].into()).type_name(), "BYTES");
885 assert_eq!(Value::List(vec![].into()).type_name(), "LIST");
886 assert_eq!(Value::Map(BTreeMap::new().into()).type_name(), "MAP");
887 assert_eq!(Value::Vector(vec![].into()).type_name(), "VECTOR");
888 }
889
890 #[test]
891 fn test_value_vector() {
892 let v = Value::Vector(vec![0.1f32, 0.2, 0.3].into());
894 assert!(v.is_vector());
895 assert_eq!(v.vector_dimensions(), Some(3));
896 assert_eq!(v.as_vector(), Some(&[0.1f32, 0.2, 0.3][..]));
897
898 let slice: &[f32] = &[1.0, 2.0, 3.0, 4.0];
900 let v2: Value = slice.into();
901 assert!(v2.is_vector());
902 assert_eq!(v2.vector_dimensions(), Some(4));
903
904 let arc: Arc<[f32]> = vec![5.0f32, 6.0].into();
906 let v3: Value = arc.into();
907 assert!(v3.is_vector());
908 assert_eq!(v3.vector_dimensions(), Some(2));
909
910 assert!(!Value::Int64(42).is_vector());
912 assert_eq!(Value::Int64(42).as_vector(), None);
913 assert_eq!(Value::Int64(42).vector_dimensions(), None);
914 }
915
916 #[test]
917 fn test_hashable_value_vector() {
918 use std::collections::HashMap;
919
920 let mut map: HashMap<HashableValue, i32> = HashMap::new();
921
922 let v1 = HashableValue::new(Value::Vector(vec![0.1f32, 0.2, 0.3].into()));
923 let v2 = HashableValue::new(Value::Vector(vec![0.1f32, 0.2, 0.3].into()));
924 let v3 = HashableValue::new(Value::Vector(vec![0.4f32, 0.5, 0.6].into()));
925
926 map.insert(v1.clone(), 1);
927
928 assert_eq!(map.get(&v2), Some(&1));
930
931 assert_eq!(map.get(&v3), None);
933
934 assert_eq!(v1, v2);
936 assert_ne!(v1, v3);
937 }
938
939 #[test]
940 fn test_orderable_value_vector_unsupported() {
941 let v = Value::Vector(vec![0.1f32, 0.2, 0.3].into());
943 assert!(OrderableValue::try_from(&v).is_err());
944 }
945
946 #[test]
947 fn test_hashable_value_basic() {
948 use std::collections::HashMap;
949
950 let mut map: HashMap<HashableValue, i32> = HashMap::new();
951
952 map.insert(HashableValue::new(Value::Int64(42)), 1);
954 map.insert(HashableValue::new(Value::String("test".into())), 2);
955 map.insert(HashableValue::new(Value::Bool(true)), 3);
956 map.insert(HashableValue::new(Value::Float64(std::f64::consts::PI)), 4);
957
958 assert_eq!(map.get(&HashableValue::new(Value::Int64(42))), Some(&1));
959 assert_eq!(
960 map.get(&HashableValue::new(Value::String("test".into()))),
961 Some(&2)
962 );
963 assert_eq!(map.get(&HashableValue::new(Value::Bool(true))), Some(&3));
964 assert_eq!(
965 map.get(&HashableValue::new(Value::Float64(std::f64::consts::PI))),
966 Some(&4)
967 );
968 }
969
970 #[test]
971 fn test_hashable_value_float_edge_cases() {
972 use std::collections::HashMap;
973
974 let mut map: HashMap<HashableValue, i32> = HashMap::new();
975
976 let nan = f64::NAN;
978 map.insert(HashableValue::new(Value::Float64(nan)), 1);
979 assert_eq!(map.get(&HashableValue::new(Value::Float64(nan))), Some(&1));
980
981 let pos_zero = 0.0f64;
983 let neg_zero = -0.0f64;
984 map.insert(HashableValue::new(Value::Float64(pos_zero)), 2);
985 map.insert(HashableValue::new(Value::Float64(neg_zero)), 3);
986 assert_eq!(
987 map.get(&HashableValue::new(Value::Float64(pos_zero))),
988 Some(&2)
989 );
990 assert_eq!(
991 map.get(&HashableValue::new(Value::Float64(neg_zero))),
992 Some(&3)
993 );
994 }
995
996 #[test]
997 fn test_hashable_value_equality() {
998 let v1 = HashableValue::new(Value::Int64(42));
999 let v2 = HashableValue::new(Value::Int64(42));
1000 let v3 = HashableValue::new(Value::Int64(43));
1001
1002 assert_eq!(v1, v2);
1003 assert_ne!(v1, v3);
1004 }
1005
1006 #[test]
1007 fn test_hashable_value_inner() {
1008 let hv = HashableValue::new(Value::String("hello".into()));
1009 assert_eq!(hv.inner().as_str(), Some("hello"));
1010
1011 let v = hv.into_inner();
1012 assert_eq!(v.as_str(), Some("hello"));
1013 }
1014
1015 #[test]
1016 fn test_hashable_value_conversions() {
1017 let v = Value::Int64(42);
1018 let hv: HashableValue = v.clone().into();
1019 let v2: Value = hv.into();
1020 assert_eq!(v, v2);
1021 }
1022
1023 #[test]
1024 fn test_orderable_value_try_from() {
1025 assert!(OrderableValue::try_from(&Value::Int64(42)).is_ok());
1027 assert!(OrderableValue::try_from(&Value::Float64(std::f64::consts::PI)).is_ok());
1028 assert!(OrderableValue::try_from(&Value::String("test".into())).is_ok());
1029 assert!(OrderableValue::try_from(&Value::Bool(true)).is_ok());
1030 assert!(OrderableValue::try_from(&Value::Timestamp(Timestamp::from_secs(1000))).is_ok());
1031
1032 assert!(OrderableValue::try_from(&Value::Null).is_err());
1034 assert!(OrderableValue::try_from(&Value::Bytes(vec![1, 2, 3].into())).is_err());
1035 assert!(OrderableValue::try_from(&Value::List(vec![].into())).is_err());
1036 assert!(OrderableValue::try_from(&Value::Map(BTreeMap::new().into())).is_err());
1037 }
1038
1039 #[test]
1040 fn test_orderable_value_ordering() {
1041 use std::collections::BTreeSet;
1042
1043 let mut set = BTreeSet::new();
1045 set.insert(OrderableValue::try_from(&Value::Int64(30)).unwrap());
1046 set.insert(OrderableValue::try_from(&Value::Int64(10)).unwrap());
1047 set.insert(OrderableValue::try_from(&Value::Int64(20)).unwrap());
1048
1049 let values: Vec<_> = set.iter().filter_map(|v| v.as_i64()).collect();
1050 assert_eq!(values, vec![10, 20, 30]);
1051 }
1052
1053 #[test]
1054 fn test_orderable_value_float_ordering() {
1055 let v1 = OrderableValue::try_from(&Value::Float64(1.0)).unwrap();
1056 let v2 = OrderableValue::try_from(&Value::Float64(2.0)).unwrap();
1057 let v_nan = OrderableValue::try_from(&Value::Float64(f64::NAN)).unwrap();
1058 let v_inf = OrderableValue::try_from(&Value::Float64(f64::INFINITY)).unwrap();
1059
1060 assert!(v1 < v2);
1061 assert!(v2 < v_inf);
1062 assert!(v_inf < v_nan); assert!(v_nan == v_nan); }
1065
1066 #[test]
1067 fn test_orderable_value_string_ordering() {
1068 let a = OrderableValue::try_from(&Value::String("apple".into())).unwrap();
1069 let b = OrderableValue::try_from(&Value::String("banana".into())).unwrap();
1070 let c = OrderableValue::try_from(&Value::String("cherry".into())).unwrap();
1071
1072 assert!(a < b);
1073 assert!(b < c);
1074 }
1075
1076 #[test]
1077 fn test_orderable_value_into_value() {
1078 let original = Value::Int64(42);
1079 let orderable = OrderableValue::try_from(&original).unwrap();
1080 let back = orderable.into_value();
1081 assert_eq!(original, back);
1082
1083 let original = Value::Float64(std::f64::consts::PI);
1084 let orderable = OrderableValue::try_from(&original).unwrap();
1085 let back = orderable.into_value();
1086 assert_eq!(original, back);
1087
1088 let original = Value::String("test".into());
1089 let orderable = OrderableValue::try_from(&original).unwrap();
1090 let back = orderable.into_value();
1091 assert_eq!(original, back);
1092 }
1093
1094 #[test]
1095 fn test_orderable_value_cross_type_numeric() {
1096 let i = OrderableValue::try_from(&Value::Int64(10)).unwrap();
1098 let f = OrderableValue::try_from(&Value::Float64(10.0)).unwrap();
1099
1100 assert_eq!(i, f);
1102
1103 let f2 = OrderableValue::try_from(&Value::Float64(10.5)).unwrap();
1104 assert!(i < f2);
1105 }
1106
1107 #[test]
1108 fn test_ordered_float64_nan_handling() {
1109 let nan1 = OrderedFloat64::new(f64::NAN);
1110 let nan2 = OrderedFloat64::new(f64::NAN);
1111 let inf = OrderedFloat64::new(f64::INFINITY);
1112 let neg_inf = OrderedFloat64::new(f64::NEG_INFINITY);
1113 let zero = OrderedFloat64::new(0.0);
1114
1115 assert_eq!(nan1, nan2);
1117
1118 assert!(neg_inf < zero);
1120 assert!(zero < inf);
1121 assert!(inf < nan1);
1122 }
1123}