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
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 Date(Date),
111
112 Time(Time),
114
115 Duration(Duration),
117
118 ZonedDatetime(ZonedDatetime),
120
121 List(Arc<[Value]>),
123
124 Map(Arc<BTreeMap<PropertyKey, Value>>),
126
127 Vector(Arc<[f32]>),
132
133 Path {
139 nodes: Arc<[Value]>,
141 edges: Arc<[Value]>,
143 },
144}
145
146impl Value {
147 #[inline]
149 #[must_use]
150 pub const fn is_null(&self) -> bool {
151 matches!(self, Value::Null)
152 }
153
154 #[inline]
156 #[must_use]
157 pub const fn as_bool(&self) -> Option<bool> {
158 match self {
159 Value::Bool(b) => Some(*b),
160 _ => None,
161 }
162 }
163
164 #[inline]
166 #[must_use]
167 pub const fn as_int64(&self) -> Option<i64> {
168 match self {
169 Value::Int64(i) => Some(*i),
170 _ => None,
171 }
172 }
173
174 #[inline]
176 #[must_use]
177 pub const fn as_float64(&self) -> Option<f64> {
178 match self {
179 Value::Float64(f) => Some(*f),
180 _ => None,
181 }
182 }
183
184 #[inline]
186 #[must_use]
187 pub fn as_str(&self) -> Option<&str> {
188 match self {
189 Value::String(s) => Some(s),
190 _ => None,
191 }
192 }
193
194 #[inline]
196 #[must_use]
197 pub fn as_bytes(&self) -> Option<&[u8]> {
198 match self {
199 Value::Bytes(b) => Some(b),
200 _ => None,
201 }
202 }
203
204 #[inline]
206 #[must_use]
207 pub const fn as_timestamp(&self) -> Option<Timestamp> {
208 match self {
209 Value::Timestamp(t) => Some(*t),
210 _ => None,
211 }
212 }
213
214 #[inline]
216 #[must_use]
217 pub const fn as_date(&self) -> Option<Date> {
218 match self {
219 Value::Date(d) => Some(*d),
220 _ => None,
221 }
222 }
223
224 #[inline]
226 #[must_use]
227 pub const fn as_time(&self) -> Option<Time> {
228 match self {
229 Value::Time(t) => Some(*t),
230 _ => None,
231 }
232 }
233
234 #[inline]
236 #[must_use]
237 pub const fn as_duration(&self) -> Option<Duration> {
238 match self {
239 Value::Duration(d) => Some(*d),
240 _ => None,
241 }
242 }
243
244 #[inline]
246 #[must_use]
247 pub const fn as_zoned_datetime(&self) -> Option<ZonedDatetime> {
248 match self {
249 Value::ZonedDatetime(zdt) => Some(*zdt),
250 _ => None,
251 }
252 }
253
254 #[inline]
256 #[must_use]
257 pub fn as_list(&self) -> Option<&[Value]> {
258 match self {
259 Value::List(l) => Some(l),
260 _ => None,
261 }
262 }
263
264 #[inline]
266 #[must_use]
267 pub fn as_map(&self) -> Option<&BTreeMap<PropertyKey, Value>> {
268 match self {
269 Value::Map(m) => Some(m),
270 _ => None,
271 }
272 }
273
274 #[inline]
276 #[must_use]
277 pub fn as_vector(&self) -> Option<&[f32]> {
278 match self {
279 Value::Vector(v) => Some(v),
280 _ => None,
281 }
282 }
283
284 #[inline]
286 #[must_use]
287 pub fn as_path(&self) -> Option<(&[Value], &[Value])> {
288 match self {
289 Value::Path { nodes, edges } => Some((nodes, edges)),
290 _ => None,
291 }
292 }
293
294 #[inline]
296 #[must_use]
297 pub const fn is_vector(&self) -> bool {
298 matches!(self, Value::Vector(_))
299 }
300
301 #[inline]
303 #[must_use]
304 pub fn vector_dimensions(&self) -> Option<usize> {
305 match self {
306 Value::Vector(v) => Some(v.len()),
307 _ => None,
308 }
309 }
310
311 #[must_use]
313 pub const fn type_name(&self) -> &'static str {
314 match self {
315 Value::Null => "NULL",
316 Value::Bool(_) => "BOOL",
317 Value::Int64(_) => "INT64",
318 Value::Float64(_) => "FLOAT64",
319 Value::String(_) => "STRING",
320 Value::Bytes(_) => "BYTES",
321 Value::Timestamp(_) => "TIMESTAMP",
322 Value::Date(_) => "DATE",
323 Value::Time(_) => "TIME",
324 Value::Duration(_) => "DURATION",
325 Value::ZonedDatetime(_) => "ZONED DATETIME",
326 Value::List(_) => "LIST",
327 Value::Map(_) => "MAP",
328 Value::Vector(_) => "VECTOR",
329 Value::Path { .. } => "PATH",
330 }
331 }
332
333 pub fn serialize(&self) -> Result<Vec<u8>, bincode::error::EncodeError> {
339 bincode::serde::encode_to_vec(self, bincode::config::standard())
340 }
341
342 pub fn deserialize(bytes: &[u8]) -> Result<Self, bincode::error::DecodeError> {
348 let (value, _) = bincode::serde::decode_from_slice(bytes, bincode::config::standard())?;
349 Ok(value)
350 }
351}
352
353impl fmt::Debug for Value {
354 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
355 match self {
356 Value::Null => write!(f, "Null"),
357 Value::Bool(b) => write!(f, "Bool({b})"),
358 Value::Int64(i) => write!(f, "Int64({i})"),
359 Value::Float64(fl) => write!(f, "Float64({fl})"),
360 Value::String(s) => write!(f, "String({s:?})"),
361 Value::Bytes(b) => write!(f, "Bytes([{}; {} bytes])", b.first().unwrap_or(&0), b.len()),
362 Value::Timestamp(t) => write!(f, "Timestamp({t:?})"),
363 Value::Date(d) => write!(f, "Date({d})"),
364 Value::Time(t) => write!(f, "Time({t})"),
365 Value::Duration(d) => write!(f, "Duration({d})"),
366 Value::ZonedDatetime(zdt) => write!(f, "ZonedDatetime({zdt})"),
367 Value::List(l) => write!(f, "List({l:?})"),
368 Value::Map(m) => write!(f, "Map({m:?})"),
369 Value::Vector(v) => write!(
370 f,
371 "Vector([{}; {} dims])",
372 v.first().unwrap_or(&0.0),
373 v.len()
374 ),
375 Value::Path { nodes, edges } => {
376 write!(f, "Path({} nodes, {} edges)", nodes.len(), edges.len())
377 }
378 }
379 }
380}
381
382impl fmt::Display for Value {
383 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
384 match self {
385 Value::Null => write!(f, "NULL"),
386 Value::Bool(b) => write!(f, "{b}"),
387 Value::Int64(i) => write!(f, "{i}"),
388 Value::Float64(fl) => write!(f, "{fl}"),
389 Value::String(s) => write!(f, "{s:?}"),
390 Value::Bytes(b) => write!(f, "<bytes: {} bytes>", b.len()),
391 Value::Timestamp(t) => write!(f, "{t}"),
392 Value::Date(d) => write!(f, "{d}"),
393 Value::Time(t) => write!(f, "{t}"),
394 Value::Duration(d) => write!(f, "{d}"),
395 Value::ZonedDatetime(zdt) => write!(f, "{zdt}"),
396 Value::List(l) => {
397 write!(f, "[")?;
398 for (i, v) in l.iter().enumerate() {
399 if i > 0 {
400 write!(f, ", ")?;
401 }
402 write!(f, "{v}")?;
403 }
404 write!(f, "]")
405 }
406 Value::Map(m) => {
407 write!(f, "{{")?;
408 for (i, (k, v)) in m.iter().enumerate() {
409 if i > 0 {
410 write!(f, ", ")?;
411 }
412 write!(f, "{k}: {v}")?;
413 }
414 write!(f, "}}")
415 }
416 Value::Vector(v) => {
417 write!(f, "vector([")?;
418 let show_count = v.len().min(3);
419 for (i, val) in v.iter().take(show_count).enumerate() {
420 if i > 0 {
421 write!(f, ", ")?;
422 }
423 write!(f, "{val}")?;
424 }
425 if v.len() > 3 {
426 write!(f, ", ... ({} dims)", v.len())?;
427 }
428 write!(f, "])")
429 }
430 Value::Path { nodes, edges } => {
431 write!(f, "<")?;
433 for (i, node) in nodes.iter().enumerate() {
434 if i > 0
435 && let Some(edge) = edges.get(i - 1)
436 {
437 write!(f, "-[{edge}]-")?;
438 }
439 write!(f, "({node})")?;
440 }
441 write!(f, ">")
442 }
443 }
444 }
445}
446
447impl From<bool> for Value {
449 fn from(b: bool) -> Self {
450 Value::Bool(b)
451 }
452}
453
454impl From<i64> for Value {
455 fn from(i: i64) -> Self {
456 Value::Int64(i)
457 }
458}
459
460impl From<i32> for Value {
461 fn from(i: i32) -> Self {
462 Value::Int64(i64::from(i))
463 }
464}
465
466impl From<f64> for Value {
467 fn from(f: f64) -> Self {
468 Value::Float64(f)
469 }
470}
471
472impl From<f32> for Value {
473 fn from(f: f32) -> Self {
474 Value::Float64(f64::from(f))
475 }
476}
477
478impl From<&str> for Value {
479 fn from(s: &str) -> Self {
480 Value::String(s.into())
481 }
482}
483
484impl From<String> for Value {
485 fn from(s: String) -> Self {
486 Value::String(s.into())
487 }
488}
489
490impl From<ArcStr> for Value {
491 fn from(s: ArcStr) -> Self {
492 Value::String(s)
493 }
494}
495
496impl From<Vec<u8>> for Value {
497 fn from(b: Vec<u8>) -> Self {
498 Value::Bytes(b.into())
499 }
500}
501
502impl From<&[u8]> for Value {
503 fn from(b: &[u8]) -> Self {
504 Value::Bytes(b.into())
505 }
506}
507
508impl From<Timestamp> for Value {
509 fn from(t: Timestamp) -> Self {
510 Value::Timestamp(t)
511 }
512}
513
514impl From<Date> for Value {
515 fn from(d: Date) -> Self {
516 Value::Date(d)
517 }
518}
519
520impl From<Time> for Value {
521 fn from(t: Time) -> Self {
522 Value::Time(t)
523 }
524}
525
526impl From<Duration> for Value {
527 fn from(d: Duration) -> Self {
528 Value::Duration(d)
529 }
530}
531
532impl From<ZonedDatetime> for Value {
533 fn from(zdt: ZonedDatetime) -> Self {
534 Value::ZonedDatetime(zdt)
535 }
536}
537
538impl<T: Into<Value>> From<Vec<T>> for Value {
539 fn from(v: Vec<T>) -> Self {
540 Value::List(v.into_iter().map(Into::into).collect())
541 }
542}
543
544impl From<&[f32]> for Value {
545 fn from(v: &[f32]) -> Self {
546 Value::Vector(v.into())
547 }
548}
549
550impl From<Arc<[f32]>> for Value {
551 fn from(v: Arc<[f32]>) -> Self {
552 Value::Vector(v)
553 }
554}
555
556impl<T: Into<Value>> From<Option<T>> for Value {
557 fn from(opt: Option<T>) -> Self {
558 match opt {
559 Some(v) => v.into(),
560 None => Value::Null,
561 }
562 }
563}
564
565#[derive(Clone, Debug)]
577pub struct HashableValue(pub Value);
578
579#[derive(Clone, Debug)]
611pub enum OrderableValue {
612 Int64(i64),
614 Float64(OrderedFloat64),
616 String(ArcStr),
618 Bool(bool),
620 Timestamp(Timestamp),
622 Date(Date),
624 Time(Time),
626 ZonedDatetime(ZonedDatetime),
628}
629
630#[derive(Clone, Copy, Debug)]
635pub struct OrderedFloat64(pub f64);
636
637impl OrderedFloat64 {
638 #[must_use]
640 pub const fn new(f: f64) -> Self {
641 Self(f)
642 }
643
644 #[must_use]
646 pub const fn get(&self) -> f64 {
647 self.0
648 }
649}
650
651impl PartialEq for OrderedFloat64 {
652 fn eq(&self, other: &Self) -> bool {
653 match (self.0.is_nan(), other.0.is_nan()) {
655 (true, true) => true,
656 (true, false) | (false, true) => false,
657 (false, false) => self.0 == other.0,
658 }
659 }
660}
661
662impl Eq for OrderedFloat64 {}
663
664impl PartialOrd for OrderedFloat64 {
665 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
666 Some(self.cmp(other))
667 }
668}
669
670impl Ord for OrderedFloat64 {
671 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
672 match (self.0.is_nan(), other.0.is_nan()) {
674 (true, true) => std::cmp::Ordering::Equal,
675 (true, false) => std::cmp::Ordering::Greater,
676 (false, true) => std::cmp::Ordering::Less,
677 (false, false) => {
678 self.0
680 .partial_cmp(&other.0)
681 .unwrap_or(std::cmp::Ordering::Equal)
682 }
683 }
684 }
685}
686
687impl Hash for OrderedFloat64 {
688 fn hash<H: Hasher>(&self, state: &mut H) {
689 self.0.to_bits().hash(state);
690 }
691}
692
693impl From<f64> for OrderedFloat64 {
694 fn from(f: f64) -> Self {
695 Self(f)
696 }
697}
698
699impl TryFrom<&Value> for OrderableValue {
700 type Error = ();
701
702 fn try_from(value: &Value) -> Result<Self, Self::Error> {
707 match value {
708 Value::Int64(i) => Ok(Self::Int64(*i)),
709 Value::Float64(f) => Ok(Self::Float64(OrderedFloat64(*f))),
710 Value::String(s) => Ok(Self::String(s.clone())),
711 Value::Bool(b) => Ok(Self::Bool(*b)),
712 Value::Timestamp(t) => Ok(Self::Timestamp(*t)),
713 Value::Date(d) => Ok(Self::Date(*d)),
714 Value::Time(t) => Ok(Self::Time(*t)),
715 Value::ZonedDatetime(zdt) => Ok(Self::ZonedDatetime(*zdt)),
716 Value::Null
717 | Value::Bytes(_)
718 | Value::Duration(_)
719 | Value::List(_)
720 | Value::Map(_)
721 | Value::Vector(_)
722 | Value::Path { .. } => Err(()),
723 }
724 }
725}
726
727impl OrderableValue {
728 #[must_use]
730 pub fn into_value(self) -> Value {
731 match self {
732 Self::Int64(i) => Value::Int64(i),
733 Self::Float64(f) => Value::Float64(f.0),
734 Self::String(s) => Value::String(s),
735 Self::Bool(b) => Value::Bool(b),
736 Self::Timestamp(t) => Value::Timestamp(t),
737 Self::Date(d) => Value::Date(d),
738 Self::Time(t) => Value::Time(t),
739 Self::ZonedDatetime(zdt) => Value::ZonedDatetime(zdt),
740 }
741 }
742
743 #[must_use]
745 pub const fn as_i64(&self) -> Option<i64> {
746 match self {
747 Self::Int64(i) => Some(*i),
748 _ => None,
749 }
750 }
751
752 #[must_use]
754 pub const fn as_f64(&self) -> Option<f64> {
755 match self {
756 Self::Float64(f) => Some(f.0),
757 _ => None,
758 }
759 }
760
761 #[must_use]
763 pub fn as_str(&self) -> Option<&str> {
764 match self {
765 Self::String(s) => Some(s),
766 _ => None,
767 }
768 }
769}
770
771impl PartialEq for OrderableValue {
772 fn eq(&self, other: &Self) -> bool {
773 match (self, other) {
774 (Self::Int64(a), Self::Int64(b)) => a == b,
775 (Self::Float64(a), Self::Float64(b)) => a == b,
776 (Self::String(a), Self::String(b)) => a == b,
777 (Self::Bool(a), Self::Bool(b)) => a == b,
778 (Self::Timestamp(a), Self::Timestamp(b)) => a == b,
779 (Self::Date(a), Self::Date(b)) => a == b,
780 (Self::Time(a), Self::Time(b)) => a == b,
781 (Self::ZonedDatetime(a), Self::ZonedDatetime(b)) => a == b,
782 (Self::Int64(a), Self::Float64(b)) => (*a as f64) == b.0,
784 (Self::Float64(a), Self::Int64(b)) => a.0 == (*b as f64),
785 _ => false,
786 }
787 }
788}
789
790impl Eq for OrderableValue {}
791
792impl PartialOrd for OrderableValue {
793 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
794 Some(self.cmp(other))
795 }
796}
797
798impl Ord for OrderableValue {
799 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
800 match (self, other) {
801 (Self::Int64(a), Self::Int64(b)) => a.cmp(b),
802 (Self::Float64(a), Self::Float64(b)) => a.cmp(b),
803 (Self::String(a), Self::String(b)) => a.cmp(b),
804 (Self::Bool(a), Self::Bool(b)) => a.cmp(b),
805 (Self::Timestamp(a), Self::Timestamp(b)) => a.cmp(b),
806 (Self::Date(a), Self::Date(b)) => a.cmp(b),
807 (Self::Time(a), Self::Time(b)) => a.cmp(b),
808 (Self::ZonedDatetime(a), Self::ZonedDatetime(b)) => a.cmp(b),
809 (Self::Int64(a), Self::Float64(b)) => OrderedFloat64(*a as f64).cmp(b),
811 (Self::Float64(a), Self::Int64(b)) => a.cmp(&OrderedFloat64(*b as f64)),
812 _ => self.type_ordinal().cmp(&other.type_ordinal()),
815 }
816 }
817}
818
819impl OrderableValue {
820 const fn type_ordinal(&self) -> u8 {
822 match self {
823 Self::Bool(_) => 0,
824 Self::Int64(_) => 1,
825 Self::Float64(_) => 2,
826 Self::String(_) => 3,
827 Self::Timestamp(_) => 4,
828 Self::Date(_) => 5,
829 Self::Time(_) => 6,
830 Self::ZonedDatetime(_) => 7,
831 }
832 }
833}
834
835impl Hash for OrderableValue {
836 fn hash<H: Hasher>(&self, state: &mut H) {
837 std::mem::discriminant(self).hash(state);
838 match self {
839 Self::Int64(i) => i.hash(state),
840 Self::Float64(f) => f.hash(state),
841 Self::String(s) => s.hash(state),
842 Self::Bool(b) => b.hash(state),
843 Self::Timestamp(t) => t.hash(state),
844 Self::Date(d) => d.hash(state),
845 Self::Time(t) => t.hash(state),
846 Self::ZonedDatetime(zdt) => zdt.hash(state),
847 }
848 }
849}
850
851impl HashableValue {
852 #[must_use]
854 pub fn new(value: Value) -> Self {
855 Self(value)
856 }
857
858 #[must_use]
860 pub fn inner(&self) -> &Value {
861 &self.0
862 }
863
864 #[must_use]
866 pub fn into_inner(self) -> Value {
867 self.0
868 }
869}
870
871fn hash_value<H: Hasher>(value: &Value, state: &mut H) {
873 std::mem::discriminant(value).hash(state);
874
875 match value {
876 Value::Null => {}
877 Value::Bool(b) => b.hash(state),
878 Value::Int64(i) => i.hash(state),
879 Value::Float64(f) => f.to_bits().hash(state),
880 Value::String(s) => s.hash(state),
881 Value::Bytes(b) => b.hash(state),
882 Value::Timestamp(t) => t.hash(state),
883 Value::Date(d) => d.hash(state),
884 Value::Time(t) => t.hash(state),
885 Value::Duration(d) => d.hash(state),
886 Value::ZonedDatetime(zdt) => zdt.hash(state),
887 Value::List(l) => {
888 l.len().hash(state);
889 for v in l.iter() {
890 hash_value(v, state);
891 }
892 }
893 Value::Map(m) => {
894 m.len().hash(state);
895 for (k, v) in m.iter() {
896 k.hash(state);
897 hash_value(v, state);
898 }
899 }
900 Value::Vector(v) => {
901 v.len().hash(state);
902 for &f in v.iter() {
903 f.to_bits().hash(state);
904 }
905 }
906 Value::Path { nodes, edges } => {
907 nodes.len().hash(state);
908 for v in nodes.iter() {
909 hash_value(v, state);
910 }
911 edges.len().hash(state);
912 for v in edges.iter() {
913 hash_value(v, state);
914 }
915 }
916 }
917}
918
919impl Hash for HashableValue {
920 fn hash<H: Hasher>(&self, state: &mut H) {
921 hash_value(&self.0, state);
922 }
923}
924
925fn values_hash_eq(a: &Value, b: &Value) -> bool {
927 match (a, b) {
928 (Value::Float64(a), Value::Float64(b)) => a.to_bits() == b.to_bits(),
929 (Value::List(a), Value::List(b)) => {
930 a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| values_hash_eq(x, y))
931 }
932 (Value::Map(a), Value::Map(b)) => {
933 a.len() == b.len()
934 && a.iter()
935 .all(|(k, v)| b.get(k).is_some_and(|bv| values_hash_eq(v, bv)))
936 }
937 (Value::Vector(a), Value::Vector(b)) => {
938 a.len() == b.len()
939 && a.iter()
940 .zip(b.iter())
941 .all(|(x, y)| x.to_bits() == y.to_bits())
942 }
943 (
944 Value::Path {
945 nodes: an,
946 edges: ae,
947 },
948 Value::Path {
949 nodes: bn,
950 edges: be,
951 },
952 ) => {
953 an.len() == bn.len()
954 && ae.len() == be.len()
955 && an.iter().zip(bn.iter()).all(|(x, y)| values_hash_eq(x, y))
956 && ae.iter().zip(be.iter()).all(|(x, y)| values_hash_eq(x, y))
957 }
958 _ => a == b,
959 }
960}
961
962impl PartialEq for HashableValue {
963 fn eq(&self, other: &Self) -> bool {
964 values_hash_eq(&self.0, &other.0)
965 }
966}
967
968impl Eq for HashableValue {}
969
970impl From<Value> for HashableValue {
971 fn from(value: Value) -> Self {
972 Self(value)
973 }
974}
975
976impl From<HashableValue> for Value {
977 fn from(hv: HashableValue) -> Self {
978 hv.0
979 }
980}
981
982#[cfg(test)]
983mod tests {
984 use super::*;
985
986 #[test]
987 fn test_value_type_checks() {
988 assert!(Value::Null.is_null());
989 assert!(!Value::Bool(true).is_null());
990
991 assert_eq!(Value::Bool(true).as_bool(), Some(true));
992 assert_eq!(Value::Bool(false).as_bool(), Some(false));
993 assert_eq!(Value::Int64(42).as_bool(), None);
994
995 assert_eq!(Value::Int64(42).as_int64(), Some(42));
996 assert_eq!(Value::String("test".into()).as_int64(), None);
997
998 assert_eq!(Value::Float64(1.234).as_float64(), Some(1.234));
999 assert_eq!(Value::String("hello".into()).as_str(), Some("hello"));
1000 }
1001
1002 #[test]
1003 fn test_value_from_conversions() {
1004 let v: Value = true.into();
1005 assert_eq!(v.as_bool(), Some(true));
1006
1007 let v: Value = 42i64.into();
1008 assert_eq!(v.as_int64(), Some(42));
1009
1010 let v: Value = 1.234f64.into();
1011 assert_eq!(v.as_float64(), Some(1.234));
1012
1013 let v: Value = "hello".into();
1014 assert_eq!(v.as_str(), Some("hello"));
1015
1016 let v: Value = vec![1u8, 2, 3].into();
1017 assert_eq!(v.as_bytes(), Some(&[1u8, 2, 3][..]));
1018 }
1019
1020 #[test]
1021 fn test_value_serialization_roundtrip() {
1022 let values = vec![
1023 Value::Null,
1024 Value::Bool(true),
1025 Value::Int64(i64::MAX),
1026 Value::Int64(i64::MIN),
1027 Value::Int64(0),
1028 Value::Float64(std::f64::consts::PI),
1029 Value::String("hello world".into()),
1030 Value::Bytes(vec![0, 1, 2, 255].into()),
1031 Value::List(vec![Value::Int64(1), Value::Int64(2)].into()),
1032 ];
1033
1034 for v in values {
1035 let bytes = v.serialize().unwrap();
1036 let decoded = Value::deserialize(&bytes).unwrap();
1037 assert_eq!(v, decoded);
1038 }
1039 }
1040
1041 #[test]
1042 fn test_property_key() {
1043 let key = PropertyKey::new("name");
1044 assert_eq!(key.as_str(), "name");
1045
1046 let key2: PropertyKey = "age".into();
1047 assert_eq!(key2.as_str(), "age");
1048
1049 assert!(key2 < key);
1051 }
1052
1053 #[test]
1054 fn test_value_type_name() {
1055 assert_eq!(Value::Null.type_name(), "NULL");
1056 assert_eq!(Value::Bool(true).type_name(), "BOOL");
1057 assert_eq!(Value::Int64(0).type_name(), "INT64");
1058 assert_eq!(Value::Float64(0.0).type_name(), "FLOAT64");
1059 assert_eq!(Value::String("".into()).type_name(), "STRING");
1060 assert_eq!(Value::Bytes(vec![].into()).type_name(), "BYTES");
1061 assert_eq!(
1062 Value::Date(Date::from_ymd(2024, 1, 15).unwrap()).type_name(),
1063 "DATE"
1064 );
1065 assert_eq!(
1066 Value::Time(Time::from_hms(12, 0, 0).unwrap()).type_name(),
1067 "TIME"
1068 );
1069 assert_eq!(Value::Duration(Duration::default()).type_name(), "DURATION");
1070 assert_eq!(Value::List(vec![].into()).type_name(), "LIST");
1071 assert_eq!(Value::Map(BTreeMap::new().into()).type_name(), "MAP");
1072 assert_eq!(Value::Vector(vec![].into()).type_name(), "VECTOR");
1073 }
1074
1075 #[test]
1076 fn test_value_vector() {
1077 let v = Value::Vector(vec![0.1f32, 0.2, 0.3].into());
1079 assert!(v.is_vector());
1080 assert_eq!(v.vector_dimensions(), Some(3));
1081 assert_eq!(v.as_vector(), Some(&[0.1f32, 0.2, 0.3][..]));
1082
1083 let slice: &[f32] = &[1.0, 2.0, 3.0, 4.0];
1085 let v2: Value = slice.into();
1086 assert!(v2.is_vector());
1087 assert_eq!(v2.vector_dimensions(), Some(4));
1088
1089 let arc: Arc<[f32]> = vec![5.0f32, 6.0].into();
1091 let v3: Value = arc.into();
1092 assert!(v3.is_vector());
1093 assert_eq!(v3.vector_dimensions(), Some(2));
1094
1095 assert!(!Value::Int64(42).is_vector());
1097 assert_eq!(Value::Int64(42).as_vector(), None);
1098 assert_eq!(Value::Int64(42).vector_dimensions(), None);
1099 }
1100
1101 #[test]
1102 fn test_hashable_value_vector() {
1103 use std::collections::HashMap;
1104
1105 let mut map: HashMap<HashableValue, i32> = HashMap::new();
1106
1107 let v1 = HashableValue::new(Value::Vector(vec![0.1f32, 0.2, 0.3].into()));
1108 let v2 = HashableValue::new(Value::Vector(vec![0.1f32, 0.2, 0.3].into()));
1109 let v3 = HashableValue::new(Value::Vector(vec![0.4f32, 0.5, 0.6].into()));
1110
1111 map.insert(v1.clone(), 1);
1112
1113 assert_eq!(map.get(&v2), Some(&1));
1115
1116 assert_eq!(map.get(&v3), None);
1118
1119 assert_eq!(v1, v2);
1121 assert_ne!(v1, v3);
1122 }
1123
1124 #[test]
1125 fn test_orderable_value_vector_unsupported() {
1126 let v = Value::Vector(vec![0.1f32, 0.2, 0.3].into());
1128 assert!(OrderableValue::try_from(&v).is_err());
1129 }
1130
1131 #[test]
1132 fn test_hashable_value_basic() {
1133 use std::collections::HashMap;
1134
1135 let mut map: HashMap<HashableValue, i32> = HashMap::new();
1136
1137 map.insert(HashableValue::new(Value::Int64(42)), 1);
1139 map.insert(HashableValue::new(Value::String("test".into())), 2);
1140 map.insert(HashableValue::new(Value::Bool(true)), 3);
1141 map.insert(HashableValue::new(Value::Float64(std::f64::consts::PI)), 4);
1142
1143 assert_eq!(map.get(&HashableValue::new(Value::Int64(42))), Some(&1));
1144 assert_eq!(
1145 map.get(&HashableValue::new(Value::String("test".into()))),
1146 Some(&2)
1147 );
1148 assert_eq!(map.get(&HashableValue::new(Value::Bool(true))), Some(&3));
1149 assert_eq!(
1150 map.get(&HashableValue::new(Value::Float64(std::f64::consts::PI))),
1151 Some(&4)
1152 );
1153 }
1154
1155 #[test]
1156 fn test_hashable_value_float_edge_cases() {
1157 use std::collections::HashMap;
1158
1159 let mut map: HashMap<HashableValue, i32> = HashMap::new();
1160
1161 let nan = f64::NAN;
1163 map.insert(HashableValue::new(Value::Float64(nan)), 1);
1164 assert_eq!(map.get(&HashableValue::new(Value::Float64(nan))), Some(&1));
1165
1166 let pos_zero = 0.0f64;
1168 let neg_zero = -0.0f64;
1169 map.insert(HashableValue::new(Value::Float64(pos_zero)), 2);
1170 map.insert(HashableValue::new(Value::Float64(neg_zero)), 3);
1171 assert_eq!(
1172 map.get(&HashableValue::new(Value::Float64(pos_zero))),
1173 Some(&2)
1174 );
1175 assert_eq!(
1176 map.get(&HashableValue::new(Value::Float64(neg_zero))),
1177 Some(&3)
1178 );
1179 }
1180
1181 #[test]
1182 fn test_hashable_value_equality() {
1183 let v1 = HashableValue::new(Value::Int64(42));
1184 let v2 = HashableValue::new(Value::Int64(42));
1185 let v3 = HashableValue::new(Value::Int64(43));
1186
1187 assert_eq!(v1, v2);
1188 assert_ne!(v1, v3);
1189 }
1190
1191 #[test]
1192 fn test_hashable_value_inner() {
1193 let hv = HashableValue::new(Value::String("hello".into()));
1194 assert_eq!(hv.inner().as_str(), Some("hello"));
1195
1196 let v = hv.into_inner();
1197 assert_eq!(v.as_str(), Some("hello"));
1198 }
1199
1200 #[test]
1201 fn test_hashable_value_conversions() {
1202 let v = Value::Int64(42);
1203 let hv: HashableValue = v.clone().into();
1204 let v2: Value = hv.into();
1205 assert_eq!(v, v2);
1206 }
1207
1208 #[test]
1209 fn test_orderable_value_try_from() {
1210 assert!(OrderableValue::try_from(&Value::Int64(42)).is_ok());
1212 assert!(OrderableValue::try_from(&Value::Float64(std::f64::consts::PI)).is_ok());
1213 assert!(OrderableValue::try_from(&Value::String("test".into())).is_ok());
1214 assert!(OrderableValue::try_from(&Value::Bool(true)).is_ok());
1215 assert!(OrderableValue::try_from(&Value::Timestamp(Timestamp::from_secs(1000))).is_ok());
1216 assert!(
1217 OrderableValue::try_from(&Value::Date(Date::from_ymd(2024, 1, 15).unwrap())).is_ok()
1218 );
1219 assert!(OrderableValue::try_from(&Value::Time(Time::from_hms(12, 0, 0).unwrap())).is_ok());
1220
1221 assert!(OrderableValue::try_from(&Value::Null).is_err());
1223 assert!(OrderableValue::try_from(&Value::Bytes(vec![1, 2, 3].into())).is_err());
1224 assert!(OrderableValue::try_from(&Value::Duration(Duration::default())).is_err());
1225 assert!(OrderableValue::try_from(&Value::List(vec![].into())).is_err());
1226 assert!(OrderableValue::try_from(&Value::Map(BTreeMap::new().into())).is_err());
1227 }
1228
1229 #[test]
1230 fn test_orderable_value_ordering() {
1231 use std::collections::BTreeSet;
1232
1233 let mut set = BTreeSet::new();
1235 set.insert(OrderableValue::try_from(&Value::Int64(30)).unwrap());
1236 set.insert(OrderableValue::try_from(&Value::Int64(10)).unwrap());
1237 set.insert(OrderableValue::try_from(&Value::Int64(20)).unwrap());
1238 set.insert(OrderableValue::try_from(&Value::Int64(i64::MIN)).unwrap());
1239 set.insert(OrderableValue::try_from(&Value::Int64(i64::MAX)).unwrap());
1240
1241 let values: Vec<_> = set.iter().filter_map(|v| v.as_i64()).collect();
1242 assert_eq!(values, vec![i64::MIN, 10, 20, 30, i64::MAX]);
1243 }
1244
1245 #[test]
1246 fn test_orderable_value_float_ordering() {
1247 let v1 = OrderableValue::try_from(&Value::Float64(1.0)).unwrap();
1248 let v2 = OrderableValue::try_from(&Value::Float64(2.0)).unwrap();
1249 let v_nan = OrderableValue::try_from(&Value::Float64(f64::NAN)).unwrap();
1250 let v_inf = OrderableValue::try_from(&Value::Float64(f64::INFINITY)).unwrap();
1251
1252 assert!(v1 < v2);
1253 assert!(v2 < v_inf);
1254 assert!(v_inf < v_nan); assert!(v_nan == v_nan); }
1257
1258 #[test]
1259 fn test_orderable_value_string_ordering() {
1260 let a = OrderableValue::try_from(&Value::String("apple".into())).unwrap();
1261 let b = OrderableValue::try_from(&Value::String("banana".into())).unwrap();
1262 let c = OrderableValue::try_from(&Value::String("cherry".into())).unwrap();
1263
1264 assert!(a < b);
1265 assert!(b < c);
1266 }
1267
1268 #[test]
1269 fn test_orderable_value_into_value() {
1270 let original = Value::Int64(42);
1271 let orderable = OrderableValue::try_from(&original).unwrap();
1272 let back = orderable.into_value();
1273 assert_eq!(original, back);
1274
1275 let original = Value::Float64(std::f64::consts::PI);
1276 let orderable = OrderableValue::try_from(&original).unwrap();
1277 let back = orderable.into_value();
1278 assert_eq!(original, back);
1279
1280 let original = Value::String("test".into());
1281 let orderable = OrderableValue::try_from(&original).unwrap();
1282 let back = orderable.into_value();
1283 assert_eq!(original, back);
1284 }
1285
1286 #[test]
1287 fn test_orderable_value_cross_type_numeric() {
1288 let i = OrderableValue::try_from(&Value::Int64(10)).unwrap();
1290 let f = OrderableValue::try_from(&Value::Float64(10.0)).unwrap();
1291
1292 assert_eq!(i, f);
1294
1295 let f2 = OrderableValue::try_from(&Value::Float64(10.5)).unwrap();
1296 assert!(i < f2);
1297 }
1298
1299 #[test]
1300 fn test_ordered_float64_nan_handling() {
1301 let nan1 = OrderedFloat64::new(f64::NAN);
1302 let nan2 = OrderedFloat64::new(f64::NAN);
1303 let inf = OrderedFloat64::new(f64::INFINITY);
1304 let neg_inf = OrderedFloat64::new(f64::NEG_INFINITY);
1305 let zero = OrderedFloat64::new(0.0);
1306
1307 assert_eq!(nan1, nan2);
1309
1310 assert!(neg_inf < zero);
1312 assert!(zero < inf);
1313 assert!(inf < nan1);
1314 }
1315
1316 #[test]
1317 fn test_value_temporal_accessors() {
1318 let date = Date::from_ymd(2024, 3, 15).unwrap();
1319 let time = Time::from_hms(14, 30, 0).unwrap();
1320 let dur = Duration::from_months(3);
1321
1322 let vd = Value::Date(date);
1323 let vt = Value::Time(time);
1324 let vr = Value::Duration(dur);
1325
1326 assert_eq!(vd.as_date(), Some(date));
1327 assert_eq!(vt.as_time(), Some(time));
1328 assert_eq!(vr.as_duration(), Some(dur));
1329
1330 assert_eq!(vd.as_time(), None);
1332 assert_eq!(vt.as_date(), None);
1333 assert_eq!(vd.as_duration(), None);
1334 }
1335
1336 #[test]
1337 fn test_value_temporal_from_conversions() {
1338 let date = Date::from_ymd(2024, 1, 15).unwrap();
1339 let v: Value = date.into();
1340 assert_eq!(v.as_date(), Some(date));
1341
1342 let time = Time::from_hms(10, 30, 0).unwrap();
1343 let v: Value = time.into();
1344 assert_eq!(v.as_time(), Some(time));
1345
1346 let dur = Duration::from_days(7);
1347 let v: Value = dur.into();
1348 assert_eq!(v.as_duration(), Some(dur));
1349 }
1350
1351 #[test]
1352 fn test_value_temporal_display() {
1353 let v = Value::Date(Date::from_ymd(2024, 3, 15).unwrap());
1354 assert_eq!(format!("{v}"), "2024-03-15");
1355
1356 let v = Value::Time(Time::from_hms(14, 30, 0).unwrap());
1357 assert_eq!(format!("{v}"), "14:30:00");
1358
1359 let v = Value::Duration(Duration::from_days(7));
1360 assert_eq!(format!("{v}"), "P7D");
1361 }
1362
1363 #[test]
1364 fn test_value_temporal_serialization_roundtrip() {
1365 let values = vec![
1366 Value::Date(Date::from_ymd(2024, 6, 15).unwrap()),
1367 Value::Time(Time::from_hms(23, 59, 59).unwrap()),
1368 Value::Duration(Duration::new(1, 2, 3_000_000_000)),
1369 ];
1370
1371 for v in values {
1372 let bytes = v.serialize().unwrap();
1373 let decoded = Value::deserialize(&bytes).unwrap();
1374 assert_eq!(v, decoded);
1375 }
1376 }
1377
1378 #[test]
1379 fn test_orderable_value_date_ordering() {
1380 let d1 =
1381 OrderableValue::try_from(&Value::Date(Date::from_ymd(2024, 1, 1).unwrap())).unwrap();
1382 let d2 =
1383 OrderableValue::try_from(&Value::Date(Date::from_ymd(2024, 6, 15).unwrap())).unwrap();
1384 assert!(d1 < d2);
1385
1386 let back = d1.into_value();
1387 assert_eq!(back.as_date(), Some(Date::from_ymd(2024, 1, 1).unwrap()));
1388 }
1389
1390 #[test]
1391 fn test_hashable_value_temporal() {
1392 use std::collections::HashMap;
1393
1394 let mut map: HashMap<HashableValue, i32> = HashMap::new();
1395
1396 let date_val = Value::Date(Date::from_ymd(2024, 3, 15).unwrap());
1397 map.insert(HashableValue::new(date_val.clone()), 1);
1398 assert_eq!(map.get(&HashableValue::new(date_val)), Some(&1));
1399
1400 let time_val = Value::Time(Time::from_hms(12, 0, 0).unwrap());
1401 map.insert(HashableValue::new(time_val.clone()), 2);
1402 assert_eq!(map.get(&HashableValue::new(time_val)), Some(&2));
1403
1404 let dur_val = Value::Duration(Duration::from_months(6));
1405 map.insert(HashableValue::new(dur_val.clone()), 3);
1406 assert_eq!(map.get(&HashableValue::new(dur_val)), Some(&3));
1407 }
1408
1409 #[test]
1412 fn test_value_path_construction_and_equality() {
1413 let path1 = Value::Path {
1414 nodes: vec![Value::Int64(1), Value::Int64(2), Value::Int64(3)].into(),
1415 edges: vec![Value::String("KNOWS".into()), Value::String("LIKES".into())].into(),
1416 };
1417 let path2 = Value::Path {
1418 nodes: vec![Value::Int64(1), Value::Int64(2), Value::Int64(3)].into(),
1419 edges: vec![Value::String("KNOWS".into()), Value::String("LIKES".into())].into(),
1420 };
1421 let path3 = Value::Path {
1422 nodes: vec![Value::Int64(1), Value::Int64(2)].into(),
1423 edges: vec![Value::String("KNOWS".into())].into(),
1424 };
1425
1426 assert_eq!(path1, path2, "Identical paths should be equal");
1427 assert_ne!(path1, path3, "Different paths should not be equal");
1428 }
1429
1430 #[test]
1431 fn test_value_path_type_name() {
1432 let path = Value::Path {
1433 nodes: vec![Value::Int64(1)].into(),
1434 edges: vec![].into(),
1435 };
1436 assert_eq!(path.type_name(), "PATH");
1437 }
1438
1439 #[test]
1440 fn test_value_path_serialization_roundtrip() {
1441 let path = Value::Path {
1442 nodes: vec![
1443 Value::String("node_a".into()),
1444 Value::String("node_b".into()),
1445 ]
1446 .into(),
1447 edges: vec![Value::String("CONNECTS".into())].into(),
1448 };
1449
1450 let bytes = path.serialize().unwrap();
1451 let decoded = Value::deserialize(&bytes).unwrap();
1452 assert_eq!(path, decoded);
1453 }
1454
1455 #[test]
1456 fn test_value_path_hashing() {
1457 use std::collections::HashMap;
1458
1459 let path1 = Value::Path {
1460 nodes: vec![Value::Int64(1), Value::Int64(2)].into(),
1461 edges: vec![Value::String("KNOWS".into())].into(),
1462 };
1463 let path2 = Value::Path {
1464 nodes: vec![Value::Int64(1), Value::Int64(2)].into(),
1465 edges: vec![Value::String("KNOWS".into())].into(),
1466 };
1467
1468 let mut map: HashMap<HashableValue, i32> = HashMap::new();
1469 map.insert(HashableValue::new(path1), 42);
1470 assert_eq!(map.get(&HashableValue::new(path2)), Some(&42));
1471 }
1472
1473 #[test]
1476 fn test_nested_list_serialization_roundtrip() {
1477 let nested = Value::List(
1478 vec![
1479 Value::List(vec![Value::Int64(1), Value::Int64(2)].into()),
1480 Value::List(vec![Value::Int64(3), Value::Int64(4)].into()),
1481 ]
1482 .into(),
1483 );
1484
1485 let bytes = nested.serialize().unwrap();
1486 let decoded = Value::deserialize(&bytes).unwrap();
1487 assert_eq!(nested, decoded);
1488 }
1489
1490 #[test]
1491 fn test_map_with_entries_serialization_roundtrip() {
1492 let mut entries = BTreeMap::new();
1493 entries.insert(PropertyKey::new("name"), Value::String("Alix".into()));
1494 entries.insert(PropertyKey::new("age"), Value::Int64(30));
1495 entries.insert(PropertyKey::new("active"), Value::Bool(true));
1496
1497 let map = Value::Map(entries.into());
1498
1499 let bytes = map.serialize().unwrap();
1500 let decoded = Value::deserialize(&bytes).unwrap();
1501 assert_eq!(map, decoded);
1502 }
1503
1504 #[test]
1505 fn test_mixed_type_list_serialization_roundtrip() {
1506 let mixed = Value::List(
1507 vec![
1508 Value::Int64(1),
1509 Value::String("hello".into()),
1510 Value::Null,
1511 Value::Bool(false),
1512 Value::Float64(3.125),
1513 ]
1514 .into(),
1515 );
1516
1517 let bytes = mixed.serialize().unwrap();
1518 let decoded = Value::deserialize(&bytes).unwrap();
1519 assert_eq!(mixed, decoded);
1520 }
1521
1522 #[test]
1523 fn test_map_with_nested_list() {
1524 let mut entries = BTreeMap::new();
1525 entries.insert(
1526 PropertyKey::new("tags"),
1527 Value::List(vec![Value::String("a".into()), Value::String("b".into())].into()),
1528 );
1529 entries.insert(PropertyKey::new("count"), Value::Int64(2));
1530
1531 let map = Value::Map(entries.into());
1532
1533 let bytes = map.serialize().unwrap();
1534 let decoded = Value::deserialize(&bytes).unwrap();
1535 assert_eq!(map, decoded);
1536 }
1537
1538 #[test]
1539 fn test_list_with_nested_map() {
1540 let mut inner_map = BTreeMap::new();
1541 inner_map.insert(PropertyKey::new("key"), Value::String("val".into()));
1542
1543 let list = Value::List(vec![Value::Map(inner_map.into()), Value::Int64(42)].into());
1544
1545 let bytes = list.serialize().unwrap();
1546 let decoded = Value::deserialize(&bytes).unwrap();
1547 assert_eq!(list, decoded);
1548 }
1549}