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::{Date, Duration, Time, Timestamp, ZonedDatetime};
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
67impl std::borrow::Borrow<str> for PropertyKey {
68 fn borrow(&self) -> &str {
69 &self.0
70 }
71}
72
73#[derive(Clone, PartialEq, Serialize, Deserialize)]
93#[non_exhaustive]
94pub enum Value {
95 Null,
97
98 Bool(bool),
100
101 Int64(i64),
103
104 Float64(f64),
106
107 String(ArcStr),
109
110 Bytes(Arc<[u8]>),
112
113 Timestamp(Timestamp),
115
116 Date(Date),
118
119 Time(Time),
121
122 Duration(Duration),
124
125 ZonedDatetime(ZonedDatetime),
127
128 List(Arc<[Value]>),
130
131 Map(Arc<BTreeMap<PropertyKey, Value>>),
133
134 Vector(Arc<[f32]>),
139
140 Path {
146 nodes: Arc<[Value]>,
148 edges: Arc<[Value]>,
150 },
151
152 GCounter(Arc<std::collections::HashMap<String, u64>>),
161
162 OnCounter {
169 pos: Arc<std::collections::HashMap<String, u64>>,
171 neg: Arc<std::collections::HashMap<String, u64>>,
174 },
175}
176
177impl Value {
178 #[inline]
180 #[must_use]
181 pub const fn is_null(&self) -> bool {
182 matches!(self, Value::Null)
183 }
184
185 #[inline]
187 #[must_use]
188 pub const fn as_bool(&self) -> Option<bool> {
189 match self {
190 Value::Bool(b) => Some(*b),
191 _ => None,
192 }
193 }
194
195 #[inline]
197 #[must_use]
198 pub const fn as_int64(&self) -> Option<i64> {
199 match self {
200 Value::Int64(i) => Some(*i),
201 _ => None,
202 }
203 }
204
205 #[inline]
207 #[must_use]
208 pub const fn as_float64(&self) -> Option<f64> {
209 match self {
210 Value::Float64(f) => Some(*f),
211 _ => None,
212 }
213 }
214
215 #[inline]
217 #[must_use]
218 pub fn as_str(&self) -> Option<&str> {
219 match self {
220 Value::String(s) => Some(s),
221 _ => None,
222 }
223 }
224
225 #[inline]
227 #[must_use]
228 pub fn as_bytes(&self) -> Option<&[u8]> {
229 match self {
230 Value::Bytes(b) => Some(b),
231 _ => None,
232 }
233 }
234
235 #[inline]
237 #[must_use]
238 pub const fn as_timestamp(&self) -> Option<Timestamp> {
239 match self {
240 Value::Timestamp(t) => Some(*t),
241 _ => None,
242 }
243 }
244
245 #[inline]
247 #[must_use]
248 pub const fn as_date(&self) -> Option<Date> {
249 match self {
250 Value::Date(d) => Some(*d),
251 _ => None,
252 }
253 }
254
255 #[inline]
257 #[must_use]
258 pub const fn as_time(&self) -> Option<Time> {
259 match self {
260 Value::Time(t) => Some(*t),
261 _ => None,
262 }
263 }
264
265 #[inline]
267 #[must_use]
268 pub const fn as_duration(&self) -> Option<Duration> {
269 match self {
270 Value::Duration(d) => Some(*d),
271 _ => None,
272 }
273 }
274
275 #[inline]
277 #[must_use]
278 pub const fn as_zoned_datetime(&self) -> Option<ZonedDatetime> {
279 match self {
280 Value::ZonedDatetime(zdt) => Some(*zdt),
281 _ => None,
282 }
283 }
284
285 #[inline]
287 #[must_use]
288 pub fn as_list(&self) -> Option<&[Value]> {
289 match self {
290 Value::List(l) => Some(l),
291 _ => None,
292 }
293 }
294
295 #[inline]
297 #[must_use]
298 pub fn as_map(&self) -> Option<&BTreeMap<PropertyKey, Value>> {
299 match self {
300 Value::Map(m) => Some(m),
301 _ => None,
302 }
303 }
304
305 #[inline]
307 #[must_use]
308 pub fn as_vector(&self) -> Option<&[f32]> {
309 match self {
310 Value::Vector(v) => Some(v),
311 _ => None,
312 }
313 }
314
315 #[inline]
317 #[must_use]
318 pub fn as_path(&self) -> Option<(&[Value], &[Value])> {
319 match self {
320 Value::Path { nodes, edges } => Some((nodes, edges)),
321 _ => None,
322 }
323 }
324
325 #[inline]
327 #[must_use]
328 pub const fn is_vector(&self) -> bool {
329 matches!(self, Value::Vector(_))
330 }
331
332 #[inline]
334 #[must_use]
335 pub fn vector_dimensions(&self) -> Option<usize> {
336 match self {
337 Value::Vector(v) => Some(v.len()),
338 _ => None,
339 }
340 }
341
342 #[must_use]
344 pub const fn type_name(&self) -> &'static str {
345 match self {
346 Value::Null => "NULL",
347 Value::Bool(_) => "BOOL",
348 Value::Int64(_) => "INT64",
349 Value::Float64(_) => "FLOAT64",
350 Value::String(_) => "STRING",
351 Value::Bytes(_) => "BYTES",
352 Value::Timestamp(_) => "TIMESTAMP",
353 Value::Date(_) => "DATE",
354 Value::Time(_) => "TIME",
355 Value::Duration(_) => "DURATION",
356 Value::ZonedDatetime(_) => "ZONED DATETIME",
357 Value::List(_) => "LIST",
358 Value::Map(_) => "MAP",
359 Value::Vector(_) => "VECTOR",
360 Value::Path { .. } => "PATH",
361 Value::GCounter(_) => "GCOUNTER",
362 Value::OnCounter { .. } => "PNCOUNTER",
363 }
364 }
365
366 pub fn serialize(&self) -> Result<Vec<u8>, bincode::error::EncodeError> {
372 bincode::serde::encode_to_vec(self, bincode::config::standard())
373 }
374
375 pub fn deserialize(bytes: &[u8]) -> Result<Self, bincode::error::DecodeError> {
381 let (value, _) = bincode::serde::decode_from_slice(bytes, bincode::config::standard())?;
382 Ok(value)
383 }
384
385 #[must_use]
391 pub fn estimated_size_bytes(&self) -> usize {
392 match self {
393 Value::Null
394 | Value::Bool(_)
395 | Value::Int64(_)
396 | Value::Float64(_)
397 | Value::Timestamp(_)
398 | Value::Date(_)
399 | Value::Time(_)
400 | Value::Duration(_)
401 | Value::ZonedDatetime(_) => 0,
402 Value::String(s) => s.len(),
403 Value::Bytes(b) => b.len(),
404 Value::Vector(v) => v.len() * size_of::<f32>(),
405 Value::List(items) => {
406 items.iter().map(Value::estimated_size_bytes).sum::<usize>()
407 + items.len() * size_of::<Value>()
408 }
409 Value::Map(m) => m
410 .iter()
411 .map(|(k, v)| k.as_ref().len() + v.estimated_size_bytes() + size_of::<Value>())
412 .sum(),
413 Value::Path { nodes, edges } => {
414 let n: usize = nodes.iter().map(Value::estimated_size_bytes).sum::<usize>()
415 + nodes.len() * size_of::<Value>();
416 let e: usize = edges.iter().map(Value::estimated_size_bytes).sum::<usize>()
417 + edges.len() * size_of::<Value>();
418 n + e
419 }
420 Value::GCounter(m) => m.keys().map(|k| k.len() + size_of::<u64>()).sum(),
421 Value::OnCounter { pos, neg } => {
422 let p: usize = pos.keys().map(|k| k.len() + size_of::<u64>()).sum();
423 let n: usize = neg.keys().map(|k| k.len() + size_of::<u64>()).sum();
424 p + n
425 }
426 }
427 }
428}
429
430impl fmt::Debug for Value {
431 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
432 match self {
433 Value::Null => write!(f, "Null"),
434 Value::Bool(b) => write!(f, "Bool({b})"),
435 Value::Int64(i) => write!(f, "Int64({i})"),
436 Value::Float64(fl) => write!(f, "Float64({fl})"),
437 Value::String(s) => write!(f, "String({s:?})"),
438 Value::Bytes(b) => write!(f, "Bytes([{}; {} bytes])", b.first().unwrap_or(&0), b.len()),
439 Value::Timestamp(t) => write!(f, "Timestamp({t:?})"),
440 Value::Date(d) => write!(f, "Date({d})"),
441 Value::Time(t) => write!(f, "Time({t})"),
442 Value::Duration(d) => write!(f, "Duration({d})"),
443 Value::ZonedDatetime(zdt) => write!(f, "ZonedDatetime({zdt})"),
444 Value::List(l) => write!(f, "List({l:?})"),
445 Value::Map(m) => write!(f, "Map({m:?})"),
446 Value::Vector(v) => write!(
447 f,
448 "Vector([{}; {} dims])",
449 v.first().unwrap_or(&0.0),
450 v.len()
451 ),
452 Value::Path { nodes, edges } => {
453 write!(f, "Path({} nodes, {} edges)", nodes.len(), edges.len())
454 }
455 Value::GCounter(counts) => {
456 let total: u64 = counts.values().sum();
457 write!(f, "GCounter(total={total}, replicas={})", counts.len())
458 }
459 Value::OnCounter { pos, neg } => {
460 let pos_sum: u128 = pos.values().copied().map(u128::from).sum();
461 let neg_sum: u128 = neg.values().copied().map(u128::from).sum();
462 if pos_sum >= neg_sum {
463 write!(f, "OnCounter(net={})", pos_sum - neg_sum)
464 } else {
465 write!(f, "OnCounter(net=-{})", neg_sum - pos_sum)
466 }
467 }
468 }
469 }
470}
471
472impl fmt::Display for Value {
473 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
474 match self {
475 Value::Null => write!(f, "NULL"),
476 Value::Bool(b) => write!(f, "{b}"),
477 Value::Int64(i) => write!(f, "{i}"),
478 Value::Float64(fl) => write!(f, "{fl}"),
479 Value::String(s) => write!(f, "{s:?}"),
480 Value::Bytes(b) => write!(f, "<bytes: {} bytes>", b.len()),
481 Value::Timestamp(t) => write!(f, "{t}"),
482 Value::Date(d) => write!(f, "{d}"),
483 Value::Time(t) => write!(f, "{t}"),
484 Value::Duration(d) => write!(f, "{d}"),
485 Value::ZonedDatetime(zdt) => write!(f, "{zdt}"),
486 Value::List(l) => {
487 write!(f, "[")?;
488 for (i, v) in l.iter().enumerate() {
489 if i > 0 {
490 write!(f, ", ")?;
491 }
492 write!(f, "{v}")?;
493 }
494 write!(f, "]")
495 }
496 Value::Map(m) => {
497 write!(f, "{{")?;
498 for (i, (k, v)) in m.iter().enumerate() {
499 if i > 0 {
500 write!(f, ", ")?;
501 }
502 write!(f, "{k}: {v}")?;
503 }
504 write!(f, "}}")
505 }
506 Value::Vector(v) => {
507 write!(f, "vector([")?;
508 let show_count = v.len().min(3);
509 for (i, val) in v.iter().take(show_count).enumerate() {
510 if i > 0 {
511 write!(f, ", ")?;
512 }
513 write!(f, "{val}")?;
514 }
515 if v.len() > 3 {
516 write!(f, ", ... ({} dims)", v.len())?;
517 }
518 write!(f, "])")
519 }
520 Value::Path { nodes, edges } => {
521 write!(f, "<")?;
523 for (i, node) in nodes.iter().enumerate() {
524 if i > 0
525 && let Some(edge) = edges.get(i - 1)
526 {
527 write!(f, "-[{edge}]-")?;
528 }
529 write!(f, "({node})")?;
530 }
531 write!(f, ">")
532 }
533 Value::GCounter(counts) => {
534 let total: u64 = counts.values().sum();
535 write!(f, "GCounter({total})")
536 }
537 Value::OnCounter { pos, neg } => {
538 let pos_sum: u128 = pos.values().copied().map(u128::from).sum();
539 let neg_sum: u128 = neg.values().copied().map(u128::from).sum();
540 if pos_sum >= neg_sum {
541 write!(f, "OnCounter({})", pos_sum - neg_sum)
542 } else {
543 write!(f, "OnCounter(-{})", neg_sum - pos_sum)
544 }
545 }
546 }
547 }
548}
549
550impl From<bool> for Value {
552 fn from(b: bool) -> Self {
553 Value::Bool(b)
554 }
555}
556
557impl From<i64> for Value {
558 fn from(i: i64) -> Self {
559 Value::Int64(i)
560 }
561}
562
563impl From<i32> for Value {
564 fn from(i: i32) -> Self {
565 Value::Int64(i64::from(i))
566 }
567}
568
569impl From<f64> for Value {
570 fn from(f: f64) -> Self {
571 Value::Float64(f)
572 }
573}
574
575impl From<f32> for Value {
576 fn from(f: f32) -> Self {
577 Value::Float64(f64::from(f))
578 }
579}
580
581impl From<&str> for Value {
582 fn from(s: &str) -> Self {
583 Value::String(s.into())
584 }
585}
586
587impl From<String> for Value {
588 fn from(s: String) -> Self {
589 Value::String(s.into())
590 }
591}
592
593impl From<ArcStr> for Value {
594 fn from(s: ArcStr) -> Self {
595 Value::String(s)
596 }
597}
598
599impl From<Vec<u8>> for Value {
600 fn from(b: Vec<u8>) -> Self {
601 Value::Bytes(b.into())
602 }
603}
604
605impl From<&[u8]> for Value {
606 fn from(b: &[u8]) -> Self {
607 Value::Bytes(b.into())
608 }
609}
610
611impl From<Timestamp> for Value {
612 fn from(t: Timestamp) -> Self {
613 Value::Timestamp(t)
614 }
615}
616
617impl From<Date> for Value {
618 fn from(d: Date) -> Self {
619 Value::Date(d)
620 }
621}
622
623impl From<Time> for Value {
624 fn from(t: Time) -> Self {
625 Value::Time(t)
626 }
627}
628
629impl From<Duration> for Value {
630 fn from(d: Duration) -> Self {
631 Value::Duration(d)
632 }
633}
634
635impl From<ZonedDatetime> for Value {
636 fn from(zdt: ZonedDatetime) -> Self {
637 Value::ZonedDatetime(zdt)
638 }
639}
640
641impl<T: Into<Value>> From<Vec<T>> for Value {
642 fn from(v: Vec<T>) -> Self {
643 Value::List(v.into_iter().map(Into::into).collect())
644 }
645}
646
647impl From<&[f32]> for Value {
648 fn from(v: &[f32]) -> Self {
649 Value::Vector(v.into())
650 }
651}
652
653impl From<Arc<[f32]>> for Value {
654 fn from(v: Arc<[f32]>) -> Self {
655 Value::Vector(v)
656 }
657}
658
659impl<T: Into<Value>> From<Option<T>> for Value {
660 fn from(opt: Option<T>) -> Self {
661 match opt {
662 Some(v) => v.into(),
663 None => Value::Null,
664 }
665 }
666}
667
668#[derive(Clone, Debug)]
680pub struct HashableValue(pub Value);
681
682#[derive(Clone, Debug)]
714#[non_exhaustive]
715pub enum OrderableValue {
716 Int64(i64),
718 Float64(OrderedFloat64),
720 String(ArcStr),
722 Bool(bool),
724 Timestamp(Timestamp),
726 Date(Date),
728 Time(Time),
730 ZonedDatetime(ZonedDatetime),
732}
733
734#[derive(Clone, Copy, Debug)]
739pub struct OrderedFloat64(pub f64);
740
741impl OrderedFloat64 {
742 #[must_use]
744 pub const fn new(f: f64) -> Self {
745 Self(f)
746 }
747
748 #[must_use]
750 pub const fn get(&self) -> f64 {
751 self.0
752 }
753}
754
755impl PartialEq for OrderedFloat64 {
756 fn eq(&self, other: &Self) -> bool {
757 match (self.0.is_nan(), other.0.is_nan()) {
759 (true, true) => true,
760 (true, false) | (false, true) => false,
761 (false, false) => self.0 == other.0,
762 }
763 }
764}
765
766impl Eq for OrderedFloat64 {}
767
768impl PartialOrd for OrderedFloat64 {
769 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
770 Some(self.cmp(other))
771 }
772}
773
774impl Ord for OrderedFloat64 {
775 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
776 match (self.0.is_nan(), other.0.is_nan()) {
778 (true, true) => std::cmp::Ordering::Equal,
779 (true, false) => std::cmp::Ordering::Greater,
780 (false, true) => std::cmp::Ordering::Less,
781 (false, false) => {
782 self.0
784 .partial_cmp(&other.0)
785 .unwrap_or(std::cmp::Ordering::Equal)
786 }
787 }
788 }
789}
790
791impl Hash for OrderedFloat64 {
792 fn hash<H: Hasher>(&self, state: &mut H) {
793 self.0.to_bits().hash(state);
794 }
795}
796
797impl From<f64> for OrderedFloat64 {
798 fn from(f: f64) -> Self {
799 Self(f)
800 }
801}
802
803impl TryFrom<&Value> for OrderableValue {
804 type Error = ();
805
806 fn try_from(value: &Value) -> Result<Self, Self::Error> {
811 match value {
812 Value::Int64(i) => Ok(Self::Int64(*i)),
813 Value::Float64(f) => Ok(Self::Float64(OrderedFloat64(*f))),
814 Value::String(s) => Ok(Self::String(s.clone())),
815 Value::Bool(b) => Ok(Self::Bool(*b)),
816 Value::Timestamp(t) => Ok(Self::Timestamp(*t)),
817 Value::Date(d) => Ok(Self::Date(*d)),
818 Value::Time(t) => Ok(Self::Time(*t)),
819 Value::ZonedDatetime(zdt) => Ok(Self::ZonedDatetime(*zdt)),
820 Value::Null
821 | Value::Bytes(_)
822 | Value::Duration(_)
823 | Value::List(_)
824 | Value::Map(_)
825 | Value::Vector(_)
826 | Value::Path { .. }
827 | Value::GCounter(_)
828 | Value::OnCounter { .. } => Err(()),
829 }
830 }
831}
832
833impl OrderableValue {
834 #[must_use]
836 pub fn into_value(self) -> Value {
837 match self {
838 Self::Int64(i) => Value::Int64(i),
839 Self::Float64(f) => Value::Float64(f.0),
840 Self::String(s) => Value::String(s),
841 Self::Bool(b) => Value::Bool(b),
842 Self::Timestamp(t) => Value::Timestamp(t),
843 Self::Date(d) => Value::Date(d),
844 Self::Time(t) => Value::Time(t),
845 Self::ZonedDatetime(zdt) => Value::ZonedDatetime(zdt),
846 }
847 }
848
849 #[must_use]
851 pub const fn as_i64(&self) -> Option<i64> {
852 match self {
853 Self::Int64(i) => Some(*i),
854 _ => None,
855 }
856 }
857
858 #[must_use]
860 pub const fn as_f64(&self) -> Option<f64> {
861 match self {
862 Self::Float64(f) => Some(f.0),
863 _ => None,
864 }
865 }
866
867 #[must_use]
869 pub fn as_str(&self) -> Option<&str> {
870 match self {
871 Self::String(s) => Some(s),
872 _ => None,
873 }
874 }
875}
876
877impl PartialEq for OrderableValue {
878 fn eq(&self, other: &Self) -> bool {
879 match (self, other) {
880 (Self::Int64(a), Self::Int64(b)) => a == b,
881 (Self::Float64(a), Self::Float64(b)) => a == b,
882 (Self::String(a), Self::String(b)) => a == b,
883 (Self::Bool(a), Self::Bool(b)) => a == b,
884 (Self::Timestamp(a), Self::Timestamp(b)) => a == b,
885 (Self::Date(a), Self::Date(b)) => a == b,
886 (Self::Time(a), Self::Time(b)) => a == b,
887 (Self::ZonedDatetime(a), Self::ZonedDatetime(b)) => a == b,
888 (Self::Int64(a), Self::Float64(b)) => (*a as f64) == b.0,
890 (Self::Float64(a), Self::Int64(b)) => a.0 == (*b as f64),
891 _ => false,
892 }
893 }
894}
895
896impl Eq for OrderableValue {}
897
898impl PartialOrd for OrderableValue {
899 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
900 Some(self.cmp(other))
901 }
902}
903
904impl Ord for OrderableValue {
905 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
906 match (self, other) {
907 (Self::Int64(a), Self::Int64(b)) => a.cmp(b),
908 (Self::Float64(a), Self::Float64(b)) => a.cmp(b),
909 (Self::String(a), Self::String(b)) => a.cmp(b),
910 (Self::Bool(a), Self::Bool(b)) => a.cmp(b),
911 (Self::Timestamp(a), Self::Timestamp(b)) => a.cmp(b),
912 (Self::Date(a), Self::Date(b)) => a.cmp(b),
913 (Self::Time(a), Self::Time(b)) => a.cmp(b),
914 (Self::ZonedDatetime(a), Self::ZonedDatetime(b)) => a.cmp(b),
915 (Self::Int64(a), Self::Float64(b)) => OrderedFloat64(*a as f64).cmp(b),
917 (Self::Float64(a), Self::Int64(b)) => a.cmp(&OrderedFloat64(*b as f64)),
918 _ => self.type_ordinal().cmp(&other.type_ordinal()),
921 }
922 }
923}
924
925impl OrderableValue {
926 const fn type_ordinal(&self) -> u8 {
928 match self {
929 Self::Bool(_) => 0,
930 Self::Int64(_) => 1,
931 Self::Float64(_) => 2,
932 Self::String(_) => 3,
933 Self::Timestamp(_) => 4,
934 Self::Date(_) => 5,
935 Self::Time(_) => 6,
936 Self::ZonedDatetime(_) => 7,
937 }
938 }
939}
940
941impl Hash for OrderableValue {
942 fn hash<H: Hasher>(&self, state: &mut H) {
943 std::mem::discriminant(self).hash(state);
944 match self {
945 Self::Int64(i) => i.hash(state),
946 Self::Float64(f) => f.hash(state),
947 Self::String(s) => s.hash(state),
948 Self::Bool(b) => b.hash(state),
949 Self::Timestamp(t) => t.hash(state),
950 Self::Date(d) => d.hash(state),
951 Self::Time(t) => t.hash(state),
952 Self::ZonedDatetime(zdt) => zdt.hash(state),
953 }
954 }
955}
956
957impl HashableValue {
958 #[must_use]
960 pub fn new(value: Value) -> Self {
961 Self(value)
962 }
963
964 #[must_use]
966 pub fn inner(&self) -> &Value {
967 &self.0
968 }
969
970 #[must_use]
972 pub fn into_inner(self) -> Value {
973 self.0
974 }
975}
976
977fn hash_value<H: Hasher>(value: &Value, state: &mut H) {
979 std::mem::discriminant(value).hash(state);
980
981 match value {
982 Value::Null => {}
983 Value::Bool(b) => b.hash(state),
984 Value::Int64(i) => i.hash(state),
985 Value::Float64(f) => f.to_bits().hash(state),
986 Value::String(s) => s.hash(state),
987 Value::Bytes(b) => b.hash(state),
988 Value::Timestamp(t) => t.hash(state),
989 Value::Date(d) => d.hash(state),
990 Value::Time(t) => t.hash(state),
991 Value::Duration(d) => d.hash(state),
992 Value::ZonedDatetime(zdt) => zdt.hash(state),
993 Value::List(l) => {
994 l.len().hash(state);
995 for v in l.iter() {
996 hash_value(v, state);
997 }
998 }
999 Value::Map(m) => {
1000 m.len().hash(state);
1001 for (k, v) in m.iter() {
1002 k.hash(state);
1003 hash_value(v, state);
1004 }
1005 }
1006 Value::Vector(v) => {
1007 v.len().hash(state);
1008 for &f in v.iter() {
1009 f.to_bits().hash(state);
1010 }
1011 }
1012 Value::Path { nodes, edges } => {
1013 nodes.len().hash(state);
1014 for v in nodes.iter() {
1015 hash_value(v, state);
1016 }
1017 edges.len().hash(state);
1018 for v in edges.iter() {
1019 hash_value(v, state);
1020 }
1021 }
1022 Value::GCounter(counts) => {
1023 let mut pairs: Vec<_> = counts.iter().collect();
1025 pairs.sort_by_key(|(k, _)| k.as_str());
1026 pairs.len().hash(state);
1027 for (k, v) in pairs {
1028 k.hash(state);
1029 v.hash(state);
1030 }
1031 }
1032 Value::OnCounter { pos, neg } => {
1033 let mut pos_pairs: Vec<_> = pos.iter().collect();
1034 pos_pairs.sort_by_key(|(k, _)| k.as_str());
1035 pos_pairs.len().hash(state);
1036 for (k, v) in pos_pairs {
1037 k.hash(state);
1038 v.hash(state);
1039 }
1040 let mut neg_pairs: Vec<_> = neg.iter().collect();
1041 neg_pairs.sort_by_key(|(k, _)| k.as_str());
1042 neg_pairs.len().hash(state);
1043 for (k, v) in neg_pairs {
1044 k.hash(state);
1045 v.hash(state);
1046 }
1047 }
1048 }
1049}
1050
1051impl Hash for HashableValue {
1052 fn hash<H: Hasher>(&self, state: &mut H) {
1053 hash_value(&self.0, state);
1054 }
1055}
1056
1057fn values_hash_eq(a: &Value, b: &Value) -> bool {
1059 match (a, b) {
1060 (Value::Float64(a), Value::Float64(b)) => a.to_bits() == b.to_bits(),
1061 (Value::List(a), Value::List(b)) => {
1062 a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| values_hash_eq(x, y))
1063 }
1064 (Value::Map(a), Value::Map(b)) => {
1065 a.len() == b.len()
1066 && a.iter()
1067 .all(|(k, v)| b.get(k).is_some_and(|bv| values_hash_eq(v, bv)))
1068 }
1069 (Value::Vector(a), Value::Vector(b)) => {
1070 a.len() == b.len()
1071 && a.iter()
1072 .zip(b.iter())
1073 .all(|(x, y)| x.to_bits() == y.to_bits())
1074 }
1075 (
1076 Value::Path {
1077 nodes: an,
1078 edges: ae,
1079 },
1080 Value::Path {
1081 nodes: bn,
1082 edges: be,
1083 },
1084 ) => {
1085 an.len() == bn.len()
1086 && ae.len() == be.len()
1087 && an.iter().zip(bn.iter()).all(|(x, y)| values_hash_eq(x, y))
1088 && ae.iter().zip(be.iter()).all(|(x, y)| values_hash_eq(x, y))
1089 }
1090 _ => a == b,
1091 }
1092}
1093
1094impl PartialEq for HashableValue {
1095 fn eq(&self, other: &Self) -> bool {
1096 values_hash_eq(&self.0, &other.0)
1097 }
1098}
1099
1100impl Eq for HashableValue {}
1101
1102impl From<Value> for HashableValue {
1103 fn from(value: Value) -> Self {
1104 Self(value)
1105 }
1106}
1107
1108impl From<HashableValue> for Value {
1109 fn from(hv: HashableValue) -> Self {
1110 hv.0
1111 }
1112}
1113
1114#[cfg(test)]
1115mod tests {
1116 use super::*;
1117
1118 #[test]
1119 fn test_value_type_checks() {
1120 assert!(Value::Null.is_null());
1121 assert!(!Value::Bool(true).is_null());
1122
1123 assert_eq!(Value::Bool(true).as_bool(), Some(true));
1124 assert_eq!(Value::Bool(false).as_bool(), Some(false));
1125 assert_eq!(Value::Int64(42).as_bool(), None);
1126
1127 assert_eq!(Value::Int64(42).as_int64(), Some(42));
1128 assert_eq!(Value::String("test".into()).as_int64(), None);
1129
1130 assert_eq!(Value::Float64(1.234).as_float64(), Some(1.234));
1131 assert_eq!(Value::String("hello".into()).as_str(), Some("hello"));
1132 }
1133
1134 #[test]
1135 fn test_value_from_conversions() {
1136 let v: Value = true.into();
1137 assert_eq!(v.as_bool(), Some(true));
1138
1139 let v: Value = 42i64.into();
1140 assert_eq!(v.as_int64(), Some(42));
1141
1142 let v: Value = 1.234f64.into();
1143 assert_eq!(v.as_float64(), Some(1.234));
1144
1145 let v: Value = "hello".into();
1146 assert_eq!(v.as_str(), Some("hello"));
1147
1148 let v: Value = vec![1u8, 2, 3].into();
1149 assert_eq!(v.as_bytes(), Some(&[1u8, 2, 3][..]));
1150 }
1151
1152 #[test]
1153 fn test_value_serialization_roundtrip() {
1154 let values = vec![
1155 Value::Null,
1156 Value::Bool(true),
1157 Value::Int64(i64::MAX),
1158 Value::Int64(i64::MIN),
1159 Value::Int64(0),
1160 Value::Float64(std::f64::consts::PI),
1161 Value::String("hello world".into()),
1162 Value::Bytes(vec![0, 1, 2, 255].into()),
1163 Value::List(vec![Value::Int64(1), Value::Int64(2)].into()),
1164 ];
1165
1166 for v in values {
1167 let bytes = v.serialize().unwrap();
1168 let decoded = Value::deserialize(&bytes).unwrap();
1169 assert_eq!(v, decoded);
1170 }
1171 }
1172
1173 #[test]
1174 fn test_property_key() {
1175 let key = PropertyKey::new("name");
1176 assert_eq!(key.as_str(), "name");
1177
1178 let key2: PropertyKey = "age".into();
1179 assert_eq!(key2.as_str(), "age");
1180
1181 assert!(key2 < key);
1183 }
1184
1185 #[test]
1186 fn test_value_type_name() {
1187 assert_eq!(Value::Null.type_name(), "NULL");
1188 assert_eq!(Value::Bool(true).type_name(), "BOOL");
1189 assert_eq!(Value::Int64(0).type_name(), "INT64");
1190 assert_eq!(Value::Float64(0.0).type_name(), "FLOAT64");
1191 assert_eq!(Value::String("".into()).type_name(), "STRING");
1192 assert_eq!(Value::Bytes(vec![].into()).type_name(), "BYTES");
1193 assert_eq!(
1194 Value::Date(Date::from_ymd(2024, 1, 15).unwrap()).type_name(),
1195 "DATE"
1196 );
1197 assert_eq!(
1198 Value::Time(Time::from_hms(12, 0, 0).unwrap()).type_name(),
1199 "TIME"
1200 );
1201 assert_eq!(Value::Duration(Duration::default()).type_name(), "DURATION");
1202 assert_eq!(Value::List(vec![].into()).type_name(), "LIST");
1203 assert_eq!(Value::Map(BTreeMap::new().into()).type_name(), "MAP");
1204 assert_eq!(Value::Vector(vec![].into()).type_name(), "VECTOR");
1205 }
1206
1207 #[test]
1208 fn test_value_vector() {
1209 let v = Value::Vector(vec![0.1f32, 0.2, 0.3].into());
1211 assert!(v.is_vector());
1212 assert_eq!(v.vector_dimensions(), Some(3));
1213 assert_eq!(v.as_vector(), Some(&[0.1f32, 0.2, 0.3][..]));
1214
1215 let slice: &[f32] = &[1.0, 2.0, 3.0, 4.0];
1217 let v2: Value = slice.into();
1218 assert!(v2.is_vector());
1219 assert_eq!(v2.vector_dimensions(), Some(4));
1220
1221 let arc: Arc<[f32]> = vec![5.0f32, 6.0].into();
1223 let v3: Value = arc.into();
1224 assert!(v3.is_vector());
1225 assert_eq!(v3.vector_dimensions(), Some(2));
1226
1227 assert!(!Value::Int64(42).is_vector());
1229 assert_eq!(Value::Int64(42).as_vector(), None);
1230 assert_eq!(Value::Int64(42).vector_dimensions(), None);
1231 }
1232
1233 #[test]
1234 fn test_hashable_value_vector() {
1235 use std::collections::HashMap;
1236
1237 let mut map: HashMap<HashableValue, i32> = HashMap::new();
1238
1239 let v1 = HashableValue::new(Value::Vector(vec![0.1f32, 0.2, 0.3].into()));
1240 let v2 = HashableValue::new(Value::Vector(vec![0.1f32, 0.2, 0.3].into()));
1241 let v3 = HashableValue::new(Value::Vector(vec![0.4f32, 0.5, 0.6].into()));
1242
1243 map.insert(v1.clone(), 1);
1244
1245 assert_eq!(map.get(&v2), Some(&1));
1247
1248 assert_eq!(map.get(&v3), None);
1250
1251 assert_eq!(v1, v2);
1253 assert_ne!(v1, v3);
1254 }
1255
1256 #[test]
1257 fn test_orderable_value_vector_unsupported() {
1258 let v = Value::Vector(vec![0.1f32, 0.2, 0.3].into());
1260 assert!(OrderableValue::try_from(&v).is_err());
1261 }
1262
1263 #[test]
1264 fn test_hashable_value_basic() {
1265 use std::collections::HashMap;
1266
1267 let mut map: HashMap<HashableValue, i32> = HashMap::new();
1268
1269 map.insert(HashableValue::new(Value::Int64(42)), 1);
1271 map.insert(HashableValue::new(Value::String("test".into())), 2);
1272 map.insert(HashableValue::new(Value::Bool(true)), 3);
1273 map.insert(HashableValue::new(Value::Float64(std::f64::consts::PI)), 4);
1274
1275 assert_eq!(map.get(&HashableValue::new(Value::Int64(42))), Some(&1));
1276 assert_eq!(
1277 map.get(&HashableValue::new(Value::String("test".into()))),
1278 Some(&2)
1279 );
1280 assert_eq!(map.get(&HashableValue::new(Value::Bool(true))), Some(&3));
1281 assert_eq!(
1282 map.get(&HashableValue::new(Value::Float64(std::f64::consts::PI))),
1283 Some(&4)
1284 );
1285 }
1286
1287 #[test]
1288 fn test_hashable_value_float_edge_cases() {
1289 use std::collections::HashMap;
1290
1291 let mut map: HashMap<HashableValue, i32> = HashMap::new();
1292
1293 let nan = f64::NAN;
1295 map.insert(HashableValue::new(Value::Float64(nan)), 1);
1296 assert_eq!(map.get(&HashableValue::new(Value::Float64(nan))), Some(&1));
1297
1298 let pos_zero = 0.0f64;
1300 let neg_zero = -0.0f64;
1301 map.insert(HashableValue::new(Value::Float64(pos_zero)), 2);
1302 map.insert(HashableValue::new(Value::Float64(neg_zero)), 3);
1303 assert_eq!(
1304 map.get(&HashableValue::new(Value::Float64(pos_zero))),
1305 Some(&2)
1306 );
1307 assert_eq!(
1308 map.get(&HashableValue::new(Value::Float64(neg_zero))),
1309 Some(&3)
1310 );
1311 }
1312
1313 #[test]
1314 fn test_hashable_value_equality() {
1315 let v1 = HashableValue::new(Value::Int64(42));
1316 let v2 = HashableValue::new(Value::Int64(42));
1317 let v3 = HashableValue::new(Value::Int64(43));
1318
1319 assert_eq!(v1, v2);
1320 assert_ne!(v1, v3);
1321 }
1322
1323 #[test]
1324 fn test_hashable_value_inner() {
1325 let hv = HashableValue::new(Value::String("hello".into()));
1326 assert_eq!(hv.inner().as_str(), Some("hello"));
1327
1328 let v = hv.into_inner();
1329 assert_eq!(v.as_str(), Some("hello"));
1330 }
1331
1332 #[test]
1333 fn test_hashable_value_conversions() {
1334 let v = Value::Int64(42);
1335 let hv: HashableValue = v.clone().into();
1336 let v2: Value = hv.into();
1337 assert_eq!(v, v2);
1338 }
1339
1340 #[test]
1341 fn test_orderable_value_try_from() {
1342 assert!(OrderableValue::try_from(&Value::Int64(42)).is_ok());
1344 assert!(OrderableValue::try_from(&Value::Float64(std::f64::consts::PI)).is_ok());
1345 assert!(OrderableValue::try_from(&Value::String("test".into())).is_ok());
1346 assert!(OrderableValue::try_from(&Value::Bool(true)).is_ok());
1347 assert!(OrderableValue::try_from(&Value::Timestamp(Timestamp::from_secs(1000))).is_ok());
1348 assert!(
1349 OrderableValue::try_from(&Value::Date(Date::from_ymd(2024, 1, 15).unwrap())).is_ok()
1350 );
1351 assert!(OrderableValue::try_from(&Value::Time(Time::from_hms(12, 0, 0).unwrap())).is_ok());
1352
1353 assert!(OrderableValue::try_from(&Value::Null).is_err());
1355 assert!(OrderableValue::try_from(&Value::Bytes(vec![1, 2, 3].into())).is_err());
1356 assert!(OrderableValue::try_from(&Value::Duration(Duration::default())).is_err());
1357 assert!(OrderableValue::try_from(&Value::List(vec![].into())).is_err());
1358 assert!(OrderableValue::try_from(&Value::Map(BTreeMap::new().into())).is_err());
1359 }
1360
1361 #[test]
1362 fn test_orderable_value_ordering() {
1363 use std::collections::BTreeSet;
1364
1365 let mut set = BTreeSet::new();
1367 set.insert(OrderableValue::try_from(&Value::Int64(30)).unwrap());
1368 set.insert(OrderableValue::try_from(&Value::Int64(10)).unwrap());
1369 set.insert(OrderableValue::try_from(&Value::Int64(20)).unwrap());
1370 set.insert(OrderableValue::try_from(&Value::Int64(i64::MIN)).unwrap());
1371 set.insert(OrderableValue::try_from(&Value::Int64(i64::MAX)).unwrap());
1372
1373 let values: Vec<_> = set.iter().filter_map(|v| v.as_i64()).collect();
1374 assert_eq!(values, vec![i64::MIN, 10, 20, 30, i64::MAX]);
1375 }
1376
1377 #[test]
1378 fn test_orderable_value_float_ordering() {
1379 let v1 = OrderableValue::try_from(&Value::Float64(1.0)).unwrap();
1380 let v2 = OrderableValue::try_from(&Value::Float64(2.0)).unwrap();
1381 let v_nan = OrderableValue::try_from(&Value::Float64(f64::NAN)).unwrap();
1382 let v_inf = OrderableValue::try_from(&Value::Float64(f64::INFINITY)).unwrap();
1383
1384 assert!(v1 < v2);
1385 assert!(v2 < v_inf);
1386 assert!(v_inf < v_nan); assert!(v_nan == v_nan); }
1389
1390 #[test]
1391 fn test_orderable_value_string_ordering() {
1392 let a = OrderableValue::try_from(&Value::String("apple".into())).unwrap();
1393 let b = OrderableValue::try_from(&Value::String("banana".into())).unwrap();
1394 let c = OrderableValue::try_from(&Value::String("cherry".into())).unwrap();
1395
1396 assert!(a < b);
1397 assert!(b < c);
1398 }
1399
1400 #[test]
1401 fn test_orderable_value_into_value() {
1402 let original = Value::Int64(42);
1403 let orderable = OrderableValue::try_from(&original).unwrap();
1404 let back = orderable.into_value();
1405 assert_eq!(original, back);
1406
1407 let original = Value::Float64(std::f64::consts::PI);
1408 let orderable = OrderableValue::try_from(&original).unwrap();
1409 let back = orderable.into_value();
1410 assert_eq!(original, back);
1411
1412 let original = Value::String("test".into());
1413 let orderable = OrderableValue::try_from(&original).unwrap();
1414 let back = orderable.into_value();
1415 assert_eq!(original, back);
1416 }
1417
1418 #[test]
1419 fn test_orderable_value_cross_type_numeric() {
1420 let i = OrderableValue::try_from(&Value::Int64(10)).unwrap();
1422 let f = OrderableValue::try_from(&Value::Float64(10.0)).unwrap();
1423
1424 assert_eq!(i, f);
1426
1427 let f2 = OrderableValue::try_from(&Value::Float64(10.5)).unwrap();
1428 assert!(i < f2);
1429 }
1430
1431 #[test]
1432 fn test_ordered_float64_nan_handling() {
1433 let nan1 = OrderedFloat64::new(f64::NAN);
1434 let nan2 = OrderedFloat64::new(f64::NAN);
1435 let inf = OrderedFloat64::new(f64::INFINITY);
1436 let neg_inf = OrderedFloat64::new(f64::NEG_INFINITY);
1437 let zero = OrderedFloat64::new(0.0);
1438
1439 assert_eq!(nan1, nan2);
1441
1442 assert!(neg_inf < zero);
1444 assert!(zero < inf);
1445 assert!(inf < nan1);
1446 }
1447
1448 #[test]
1449 fn test_value_temporal_accessors() {
1450 let date = Date::from_ymd(2024, 3, 15).unwrap();
1451 let time = Time::from_hms(14, 30, 0).unwrap();
1452 let dur = Duration::from_months(3);
1453
1454 let vd = Value::Date(date);
1455 let vt = Value::Time(time);
1456 let vr = Value::Duration(dur);
1457
1458 assert_eq!(vd.as_date(), Some(date));
1459 assert_eq!(vt.as_time(), Some(time));
1460 assert_eq!(vr.as_duration(), Some(dur));
1461
1462 assert_eq!(vd.as_time(), None);
1464 assert_eq!(vt.as_date(), None);
1465 assert_eq!(vd.as_duration(), None);
1466 }
1467
1468 #[test]
1469 fn test_value_temporal_from_conversions() {
1470 let date = Date::from_ymd(2024, 1, 15).unwrap();
1471 let v: Value = date.into();
1472 assert_eq!(v.as_date(), Some(date));
1473
1474 let time = Time::from_hms(10, 30, 0).unwrap();
1475 let v: Value = time.into();
1476 assert_eq!(v.as_time(), Some(time));
1477
1478 let dur = Duration::from_days(7);
1479 let v: Value = dur.into();
1480 assert_eq!(v.as_duration(), Some(dur));
1481 }
1482
1483 #[test]
1484 fn test_value_temporal_display() {
1485 let v = Value::Date(Date::from_ymd(2024, 3, 15).unwrap());
1486 assert_eq!(format!("{v}"), "2024-03-15");
1487
1488 let v = Value::Time(Time::from_hms(14, 30, 0).unwrap());
1489 assert_eq!(format!("{v}"), "14:30:00");
1490
1491 let v = Value::Duration(Duration::from_days(7));
1492 assert_eq!(format!("{v}"), "P7D");
1493 }
1494
1495 #[test]
1496 fn test_value_temporal_serialization_roundtrip() {
1497 let values = vec![
1498 Value::Date(Date::from_ymd(2024, 6, 15).unwrap()),
1499 Value::Time(Time::from_hms(23, 59, 59).unwrap()),
1500 Value::Duration(Duration::new(1, 2, 3_000_000_000)),
1501 ];
1502
1503 for v in values {
1504 let bytes = v.serialize().unwrap();
1505 let decoded = Value::deserialize(&bytes).unwrap();
1506 assert_eq!(v, decoded);
1507 }
1508 }
1509
1510 #[test]
1511 fn test_orderable_value_date_ordering() {
1512 let d1 =
1513 OrderableValue::try_from(&Value::Date(Date::from_ymd(2024, 1, 1).unwrap())).unwrap();
1514 let d2 =
1515 OrderableValue::try_from(&Value::Date(Date::from_ymd(2024, 6, 15).unwrap())).unwrap();
1516 assert!(d1 < d2);
1517
1518 let back = d1.into_value();
1519 assert_eq!(back.as_date(), Some(Date::from_ymd(2024, 1, 1).unwrap()));
1520 }
1521
1522 #[test]
1523 fn test_hashable_value_temporal() {
1524 use std::collections::HashMap;
1525
1526 let mut map: HashMap<HashableValue, i32> = HashMap::new();
1527
1528 let date_val = Value::Date(Date::from_ymd(2024, 3, 15).unwrap());
1529 map.insert(HashableValue::new(date_val.clone()), 1);
1530 assert_eq!(map.get(&HashableValue::new(date_val)), Some(&1));
1531
1532 let time_val = Value::Time(Time::from_hms(12, 0, 0).unwrap());
1533 map.insert(HashableValue::new(time_val.clone()), 2);
1534 assert_eq!(map.get(&HashableValue::new(time_val)), Some(&2));
1535
1536 let dur_val = Value::Duration(Duration::from_months(6));
1537 map.insert(HashableValue::new(dur_val.clone()), 3);
1538 assert_eq!(map.get(&HashableValue::new(dur_val)), Some(&3));
1539 }
1540
1541 #[test]
1544 fn test_value_path_construction_and_equality() {
1545 let path1 = Value::Path {
1546 nodes: vec![Value::Int64(1), Value::Int64(2), Value::Int64(3)].into(),
1547 edges: vec![Value::String("KNOWS".into()), Value::String("LIKES".into())].into(),
1548 };
1549 let path2 = Value::Path {
1550 nodes: vec![Value::Int64(1), Value::Int64(2), Value::Int64(3)].into(),
1551 edges: vec![Value::String("KNOWS".into()), Value::String("LIKES".into())].into(),
1552 };
1553 let path3 = Value::Path {
1554 nodes: vec![Value::Int64(1), Value::Int64(2)].into(),
1555 edges: vec![Value::String("KNOWS".into())].into(),
1556 };
1557
1558 assert_eq!(path1, path2, "Identical paths should be equal");
1559 assert_ne!(path1, path3, "Different paths should not be equal");
1560 }
1561
1562 #[test]
1563 fn test_value_path_type_name() {
1564 let path = Value::Path {
1565 nodes: vec![Value::Int64(1)].into(),
1566 edges: vec![].into(),
1567 };
1568 assert_eq!(path.type_name(), "PATH");
1569 }
1570
1571 #[test]
1572 fn test_value_path_serialization_roundtrip() {
1573 let path = Value::Path {
1574 nodes: vec![
1575 Value::String("node_a".into()),
1576 Value::String("node_b".into()),
1577 ]
1578 .into(),
1579 edges: vec![Value::String("CONNECTS".into())].into(),
1580 };
1581
1582 let bytes = path.serialize().unwrap();
1583 let decoded = Value::deserialize(&bytes).unwrap();
1584 assert_eq!(path, decoded);
1585 }
1586
1587 #[test]
1588 fn test_value_path_hashing() {
1589 use std::collections::HashMap;
1590
1591 let path1 = Value::Path {
1592 nodes: vec![Value::Int64(1), Value::Int64(2)].into(),
1593 edges: vec![Value::String("KNOWS".into())].into(),
1594 };
1595 let path2 = Value::Path {
1596 nodes: vec![Value::Int64(1), Value::Int64(2)].into(),
1597 edges: vec![Value::String("KNOWS".into())].into(),
1598 };
1599
1600 let mut map: HashMap<HashableValue, i32> = HashMap::new();
1601 map.insert(HashableValue::new(path1), 42);
1602 assert_eq!(map.get(&HashableValue::new(path2)), Some(&42));
1603 }
1604
1605 #[test]
1608 fn test_nested_list_serialization_roundtrip() {
1609 let nested = Value::List(
1610 vec![
1611 Value::List(vec![Value::Int64(1), Value::Int64(2)].into()),
1612 Value::List(vec![Value::Int64(3), Value::Int64(4)].into()),
1613 ]
1614 .into(),
1615 );
1616
1617 let bytes = nested.serialize().unwrap();
1618 let decoded = Value::deserialize(&bytes).unwrap();
1619 assert_eq!(nested, decoded);
1620 }
1621
1622 #[test]
1623 fn test_map_with_entries_serialization_roundtrip() {
1624 let mut entries = BTreeMap::new();
1625 entries.insert(PropertyKey::new("name"), Value::String("Alix".into()));
1626 entries.insert(PropertyKey::new("age"), Value::Int64(30));
1627 entries.insert(PropertyKey::new("active"), Value::Bool(true));
1628
1629 let map = Value::Map(entries.into());
1630
1631 let bytes = map.serialize().unwrap();
1632 let decoded = Value::deserialize(&bytes).unwrap();
1633 assert_eq!(map, decoded);
1634 }
1635
1636 #[test]
1637 fn test_mixed_type_list_serialization_roundtrip() {
1638 let mixed = Value::List(
1639 vec![
1640 Value::Int64(1),
1641 Value::String("hello".into()),
1642 Value::Null,
1643 Value::Bool(false),
1644 Value::Float64(3.125),
1645 ]
1646 .into(),
1647 );
1648
1649 let bytes = mixed.serialize().unwrap();
1650 let decoded = Value::deserialize(&bytes).unwrap();
1651 assert_eq!(mixed, decoded);
1652 }
1653
1654 #[test]
1655 fn test_map_with_nested_list() {
1656 let mut entries = BTreeMap::new();
1657 entries.insert(
1658 PropertyKey::new("tags"),
1659 Value::List(vec![Value::String("a".into()), Value::String("b".into())].into()),
1660 );
1661 entries.insert(PropertyKey::new("count"), Value::Int64(2));
1662
1663 let map = Value::Map(entries.into());
1664
1665 let bytes = map.serialize().unwrap();
1666 let decoded = Value::deserialize(&bytes).unwrap();
1667 assert_eq!(map, decoded);
1668 }
1669
1670 #[test]
1671 fn test_list_with_nested_map() {
1672 let mut inner_map = BTreeMap::new();
1673 inner_map.insert(PropertyKey::new("key"), Value::String("val".into()));
1674
1675 let list = Value::List(vec![Value::Map(inner_map.into()), Value::Int64(42)].into());
1676
1677 let bytes = list.serialize().unwrap();
1678 let decoded = Value::deserialize(&bytes).unwrap();
1679 assert_eq!(list, decoded);
1680 }
1681
1682 #[test]
1683 fn test_property_key_borrow_str() {
1684 use std::collections::HashMap;
1685 let mut map: HashMap<PropertyKey, i32> = HashMap::new();
1686 map.insert(PropertyKey::new("name"), 42);
1687 map.insert(PropertyKey::new("age"), 30);
1688 assert_eq!(map.get("name"), Some(&42));
1689 assert_eq!(map.get("age"), Some(&30));
1690 assert_eq!(map.get("missing"), None);
1691 assert!(map.contains_key("name"));
1692 assert!(!map.contains_key("nope"));
1693 }
1694
1695 #[test]
1696 fn test_gcounter_type_name() {
1697 let v = Value::GCounter(Arc::new(std::collections::HashMap::new()));
1698 assert_eq!(v.type_name(), "GCOUNTER");
1699 }
1700
1701 #[test]
1702 fn test_oncounter_type_name() {
1703 let v = Value::OnCounter {
1704 pos: Arc::new(std::collections::HashMap::new()),
1705 neg: Arc::new(std::collections::HashMap::new()),
1706 };
1707 assert_eq!(v.type_name(), "PNCOUNTER");
1708 }
1709
1710 #[test]
1711 fn test_gcounter_display() {
1712 let mut counts = std::collections::HashMap::new();
1713 counts.insert("node-a".to_string(), 10u64);
1714 counts.insert("node-b".to_string(), 5u64);
1715 let v = Value::GCounter(Arc::new(counts));
1716 assert_eq!(format!("{v}"), "GCounter(15)");
1717 }
1718
1719 #[test]
1720 fn test_gcounter_debug() {
1721 let mut counts = std::collections::HashMap::new();
1722 counts.insert("node-a".to_string(), 3u64);
1723 let v = Value::GCounter(Arc::new(counts));
1724 let debug = format!("{v:?}");
1725 assert!(debug.contains("GCounter"));
1726 assert!(debug.contains("total=3"));
1727 }
1728
1729 #[test]
1730 fn test_oncounter_display() {
1731 let mut pos = std::collections::HashMap::new();
1732 pos.insert("node-a".to_string(), 10u64);
1733 pos.insert("node-b".to_string(), 3u64);
1734 let mut neg = std::collections::HashMap::new();
1735 neg.insert("node-a".to_string(), 4u64);
1736 let v = Value::OnCounter {
1737 pos: Arc::new(pos),
1738 neg: Arc::new(neg),
1739 };
1740 assert_eq!(format!("{v}"), "OnCounter(9)");
1742 }
1743
1744 #[test]
1745 fn test_oncounter_debug() {
1746 let v = Value::OnCounter {
1747 pos: Arc::new(std::collections::HashMap::new()),
1748 neg: Arc::new(std::collections::HashMap::new()),
1749 };
1750 let debug = format!("{v:?}");
1751 assert!(debug.contains("OnCounter"));
1752 assert!(debug.contains("net=0"));
1753 }
1754
1755 #[test]
1756 fn test_gcounter_hash_is_insertion_order_independent() {
1757 use std::hash::{Hash, Hasher};
1758 let mut counts1 = std::collections::HashMap::new();
1759 counts1.insert("b".to_string(), 2u64);
1760 counts1.insert("a".to_string(), 1u64);
1761 let mut counts2 = std::collections::HashMap::new();
1762 counts2.insert("a".to_string(), 1u64);
1763 counts2.insert("b".to_string(), 2u64);
1764 let v1 = HashableValue(Value::GCounter(Arc::new(counts1)));
1765 let v2 = HashableValue(Value::GCounter(Arc::new(counts2)));
1766 let mut h1 = std::collections::hash_map::DefaultHasher::new();
1767 let mut h2 = std::collections::hash_map::DefaultHasher::new();
1768 v1.hash(&mut h1);
1769 v2.hash(&mut h2);
1770 assert_eq!(h1.finish(), h2.finish());
1771 }
1772
1773 #[test]
1774 fn test_oncounter_hash_is_insertion_order_independent() {
1775 use std::hash::{Hash, Hasher};
1776 let mut pos1 = std::collections::HashMap::new();
1777 pos1.insert("b".to_string(), 5u64);
1778 pos1.insert("a".to_string(), 3u64);
1779 let mut pos2 = std::collections::HashMap::new();
1780 pos2.insert("a".to_string(), 3u64);
1781 pos2.insert("b".to_string(), 5u64);
1782 let neg = Arc::new(std::collections::HashMap::new());
1783 let v1 = HashableValue(Value::OnCounter {
1784 pos: Arc::new(pos1),
1785 neg: neg.clone(),
1786 });
1787 let v2 = HashableValue(Value::OnCounter {
1788 pos: Arc::new(pos2),
1789 neg: neg.clone(),
1790 });
1791 let mut h1 = std::collections::hash_map::DefaultHasher::new();
1792 let mut h2 = std::collections::hash_map::DefaultHasher::new();
1793 v1.hash(&mut h1);
1794 v2.hash(&mut h2);
1795 assert_eq!(h1.finish(), h2.finish());
1796 }
1797
1798 #[test]
1799 fn test_gcounter_serialize_roundtrip() {
1800 let mut counts = std::collections::HashMap::new();
1801 counts.insert("replica-1".to_string(), 42u64);
1802 counts.insert("replica-2".to_string(), 7u64);
1803 let v = Value::GCounter(Arc::new(counts));
1804 let bytes = v.serialize().unwrap();
1805 let decoded = Value::deserialize(&bytes).unwrap();
1806 assert_eq!(v, decoded);
1807 }
1808
1809 #[test]
1810 fn test_oncounter_serialize_roundtrip() {
1811 let mut pos = std::collections::HashMap::new();
1812 pos.insert("node-a".to_string(), 10u64);
1813 let mut neg = std::collections::HashMap::new();
1814 neg.insert("node-a".to_string(), 3u64);
1815 let v = Value::OnCounter {
1816 pos: Arc::new(pos),
1817 neg: Arc::new(neg),
1818 };
1819 let bytes = v.serialize().unwrap();
1820 let decoded = Value::deserialize(&bytes).unwrap();
1821 assert_eq!(v, decoded);
1822 }
1823
1824 #[test]
1825 fn test_gcounter_empty_display() {
1826 let v = Value::GCounter(Arc::new(std::collections::HashMap::new()));
1827 assert_eq!(format!("{v}"), "GCounter(0)");
1828 }
1829
1830 #[test]
1831 fn test_oncounter_zero_net() {
1832 let mut pos = std::collections::HashMap::new();
1833 pos.insert("r".to_string(), 5u64);
1834 let mut neg = std::collections::HashMap::new();
1835 neg.insert("r".to_string(), 5u64);
1836 let v = Value::OnCounter {
1837 pos: Arc::new(pos),
1838 neg: Arc::new(neg),
1839 };
1840 assert_eq!(format!("{v}"), "OnCounter(0)");
1841 }
1842
1843 #[test]
1844 fn test_estimated_size_bytes_fixed_types() {
1845 assert_eq!(Value::Null.estimated_size_bytes(), 0);
1846 assert_eq!(Value::Bool(true).estimated_size_bytes(), 0);
1847 assert_eq!(Value::Int64(42).estimated_size_bytes(), 0);
1848 assert_eq!(Value::Float64(3.125).estimated_size_bytes(), 0);
1849 }
1850
1851 #[test]
1852 fn test_estimated_size_bytes_string() {
1853 let v = Value::from("hello");
1854 assert_eq!(v.estimated_size_bytes(), 5);
1855 }
1856
1857 #[test]
1858 fn test_estimated_size_bytes_bytes() {
1859 let v = Value::Bytes(Arc::from(vec![0u8; 100].as_slice()));
1860 assert_eq!(v.estimated_size_bytes(), 100);
1861 }
1862
1863 #[test]
1864 fn test_estimated_size_bytes_vector() {
1865 let v = Value::Vector(Arc::from(vec![1.0f32; 384].as_slice()));
1866 assert_eq!(v.estimated_size_bytes(), 384 * 4);
1867 }
1868
1869 #[test]
1870 fn test_estimated_size_bytes_list() {
1871 let v = Value::List(Arc::from(vec![Value::from("abc"), Value::Int64(1)]));
1872 assert!(v.estimated_size_bytes() >= 3);
1873 }
1874
1875 #[test]
1878 fn test_as_date_matching() {
1879 let date = Date::from_ymd(2024, 6, 15).unwrap();
1880 let v = Value::Date(date);
1881 assert_eq!(v.as_date(), Some(date));
1882 }
1883
1884 #[test]
1885 fn test_as_date_non_matching() {
1886 let v = Value::Int64(42);
1887 assert_eq!(v.as_date(), None);
1888 }
1889
1890 #[test]
1891 fn test_as_time_matching() {
1892 let time = Time::from_hms(14, 30, 0).unwrap();
1893 let v = Value::Time(time);
1894 assert_eq!(v.as_time(), Some(time));
1895 }
1896
1897 #[test]
1898 fn test_as_time_non_matching() {
1899 let v = Value::String("x".into());
1900 assert_eq!(v.as_time(), None);
1901 }
1902
1903 #[test]
1904 fn test_as_duration_matching() {
1905 let dur = Duration::new(1, 2, 3_000_000_000);
1906 let v = Value::Duration(dur);
1907 assert_eq!(v.as_duration(), Some(dur));
1908 }
1909
1910 #[test]
1911 fn test_as_duration_non_matching() {
1912 let v = Value::Bool(true);
1913 assert_eq!(v.as_duration(), None);
1914 }
1915
1916 #[test]
1917 fn test_as_zoned_datetime_matching() {
1918 let zdt = ZonedDatetime::parse("2024-06-15T10:30:00+01:00").unwrap();
1919 let v = Value::ZonedDatetime(zdt);
1920 assert_eq!(v.as_zoned_datetime(), Some(zdt));
1921 }
1922
1923 #[test]
1924 fn test_as_zoned_datetime_non_matching() {
1925 let v = Value::Null;
1926 assert_eq!(v.as_zoned_datetime(), None);
1927 }
1928
1929 #[test]
1930 fn test_as_zoned_datetime_from_conversion() {
1931 let zdt = ZonedDatetime::parse("2025-01-01T00:00:00+02:00").unwrap();
1932 let v: Value = zdt.into();
1933 assert_eq!(v.as_zoned_datetime(), Some(zdt));
1934 assert_eq!(v.type_name(), "ZONED DATETIME");
1935 }
1936
1937 #[test]
1938 fn test_as_date_wrong_temporal_type() {
1939 let time = Time::from_hms(12, 0, 0).unwrap();
1941 let v = Value::Time(time);
1942 assert_eq!(v.as_date(), None);
1943 }
1944
1945 #[test]
1946 fn test_as_time_wrong_temporal_type() {
1947 let date = Date::from_ymd(2024, 3, 15).unwrap();
1949 let v = Value::Date(date);
1950 assert_eq!(v.as_time(), None);
1951 }
1952
1953 #[test]
1954 fn test_as_duration_wrong_temporal_type() {
1955 let ts = Timestamp::from_secs(1_000_000);
1957 let v = Value::Timestamp(ts);
1958 assert_eq!(v.as_duration(), None);
1959 }
1960
1961 #[test]
1962 fn test_as_zoned_datetime_wrong_temporal_type() {
1963 let ts = Timestamp::from_secs(1_000_000);
1965 let v = Value::Timestamp(ts);
1966 assert_eq!(v.as_zoned_datetime(), None);
1967 }
1968
1969 #[test]
1970 fn test_zoned_datetime_serialization_roundtrip() {
1971 let zdt = ZonedDatetime::parse("2024-12-25T18:00:00+05:30").unwrap();
1972 let v = Value::ZonedDatetime(zdt);
1973 let bytes = v.serialize().unwrap();
1974 let decoded = Value::deserialize(&bytes).unwrap();
1975 assert_eq!(v, decoded);
1976 assert_eq!(decoded.as_zoned_datetime(), Some(zdt));
1977 }
1978
1979 #[test]
1980 fn test_zoned_datetime_type_name() {
1981 let zdt = ZonedDatetime::parse("2024-06-15T10:30:00+02:00").unwrap();
1982 let v = Value::ZonedDatetime(zdt);
1983 assert_eq!(v.type_name(), "ZONED DATETIME");
1984 }
1985
1986 #[test]
1987 fn test_zoned_datetime_display() {
1988 let zdt = ZonedDatetime::parse("2024-06-15T10:30:00+02:00").unwrap();
1989 let v = Value::ZonedDatetime(zdt);
1990 let displayed = format!("{v}");
1991 assert!(
1992 displayed.contains("2024-06-15"),
1993 "Display should contain the date"
1994 );
1995 assert!(
1996 displayed.contains("10:30:00"),
1997 "Display should contain the time"
1998 );
1999 }
2000}