1use crate::api::error::UniError;
49use crate::core::id::{Eid, Vid};
50use crate::value::{Edge, Node, Path, Value};
51use serde::{Deserialize, Serialize};
52use std::collections::{BTreeMap, HashMap};
53
54pub const TAG_NULL: u8 = 0;
56pub const TAG_BOOL: u8 = 1;
57pub const TAG_INT: u8 = 2;
58pub const TAG_FLOAT: u8 = 3;
59pub const TAG_STRING: u8 = 4;
60pub const TAG_LIST: u8 = 5;
61pub const TAG_MAP: u8 = 6;
62pub const TAG_BYTES: u8 = 7;
63pub const TAG_NODE: u8 = 8;
64pub const TAG_EDGE: u8 = 9;
65pub const TAG_PATH: u8 = 10;
66pub const TAG_DATE: u8 = 11;
67pub const TAG_TIME: u8 = 12;
68pub const TAG_DATETIME: u8 = 13;
69pub const TAG_DURATION: u8 = 14;
70pub const TAG_VECTOR: u8 = 16;
72pub const TAG_LOCALTIME: u8 = 17;
73pub const TAG_LOCALDATETIME: u8 = 18;
74pub const TAG_BTIC: u8 = 19;
75pub const TAG_SPARSE_VECTOR: u8 = 20;
76pub const TAG_BINARY_VECTOR: u8 = 21;
77
78fn decode_msgpack<'de, T: Deserialize<'de>>(
86 payload: &'de [u8],
87 type_name: &'static str,
88) -> Result<T, UniError> {
89 rmp_serde::from_slice(payload).map_err(|e| UniError::Storage {
90 message: format!("failed to decode {type_name}: {e}"),
91 source: None,
92 })
93}
94
95fn encode_msgpack<T: Serialize>(buf: &mut Vec<u8>, tag: u8, value: &T, type_name: &'static str) {
99 buf.push(tag);
100 rmp_serde::encode::write(buf, value).unwrap_or_else(|_| panic!("{type_name} encode failed"));
101}
102
103fn canonical_sparse_vector(indices: &[u32], values: &[f32]) -> uni_sparse_vector::SparseVector {
111 let pairs: Vec<(u32, f32)> = indices
112 .iter()
113 .copied()
114 .zip(values.iter().copied())
115 .filter(|&(_, w)| w.is_finite())
116 .collect();
117 uni_sparse_vector::SparseVector::from_pairs(pairs).unwrap_or_else(|_| {
120 uni_sparse_vector::SparseVector::new(Vec::new(), Vec::new())
121 .expect("empty sparse vector is always valid")
122 })
123}
124
125pub fn encode(value: &Value) -> Vec<u8> {
131 let mut buf = Vec::new();
132 encode_to_buf(value, &mut buf);
133 buf
134}
135
136pub fn decode(bytes: &[u8]) -> Result<Value, UniError> {
138 if bytes.is_empty() {
139 return Err(UniError::Storage {
140 message: "empty CypherValue bytes".to_string(),
141 source: None,
142 });
143 }
144 let tag = bytes[0];
145 let payload = &bytes[1..];
146
147 match tag {
148 TAG_NULL => Ok(Value::Null),
149 TAG_BOOL => Ok(Value::Bool(decode_msgpack(payload, "bool")?)),
150 TAG_INT => Ok(Value::Int(decode_msgpack(payload, "int")?)),
151 TAG_FLOAT => Ok(Value::Float(decode_msgpack(payload, "float")?)),
152 TAG_STRING => Ok(Value::String(decode_msgpack(payload, "string")?)),
153 TAG_BYTES => Ok(Value::Bytes(decode_msgpack(payload, "bytes")?)),
154 TAG_LIST => {
155 let blobs: Vec<Vec<u8>> = decode_msgpack(payload, "list")?;
156 let items: Result<Vec<Value>, UniError> = blobs.iter().map(|b| decode(b)).collect();
157 Ok(Value::List(items?))
158 }
159 TAG_MAP => {
160 let blob_map: HashMap<String, Vec<u8>> = decode_msgpack(payload, "map")?;
161 let mut map = HashMap::new();
162 for (k, v_blob) in blob_map {
163 map.insert(k, decode(&v_blob)?);
164 }
165 Ok(Value::Map(map))
166 }
167 TAG_NODE => {
168 let np: NodePayload = decode_msgpack(payload, "node")?;
169 let mut props = HashMap::new();
170 for (k, v_blob) in np.properties {
171 props.insert(k, decode(&v_blob)?);
172 }
173 Ok(Value::Node(Node {
174 vid: np.vid,
175 labels: np.labels,
176 properties: props,
177 }))
178 }
179 TAG_EDGE => {
180 let ep: EdgePayload = decode_msgpack(payload, "edge")?;
181 let mut props = HashMap::new();
182 for (k, v_blob) in ep.properties {
183 props.insert(k, decode(&v_blob)?);
184 }
185 Ok(Value::Edge(Edge {
186 eid: ep.eid,
187 edge_type: ep.edge_type,
188 src: ep.src,
189 dst: ep.dst,
190 properties: props,
191 }))
192 }
193 TAG_PATH => {
194 let pp: PathPayload = decode_msgpack(payload, "path")?;
195 let nodes: Result<Vec<Node>, UniError> = pp
196 .nodes
197 .iter()
198 .map(|b| match decode(b)? {
199 Value::Node(n) => Ok(n),
200 _ => Err(UniError::Storage {
201 message: "path node blob is not a Node".to_string(),
202 source: None,
203 }),
204 })
205 .collect();
206 let edges: Result<Vec<Edge>, UniError> = pp
207 .edges
208 .iter()
209 .map(|b| match decode(b)? {
210 Value::Edge(e) => Ok(e),
211 _ => Err(UniError::Storage {
212 message: "path edge blob is not an Edge".to_string(),
213 source: None,
214 }),
215 })
216 .collect();
217 Ok(Value::Path(Path {
218 nodes: nodes?,
219 edges: edges?,
220 }))
221 }
222 TAG_VECTOR => Ok(Value::Vector(decode_msgpack(payload, "vector")?)),
223 TAG_BINARY_VECTOR => Ok(Value::BinaryVector(decode_msgpack(
224 payload,
225 "binary vector",
226 )?)),
227 TAG_DATE => Ok(Value::Temporal(crate::value::TemporalValue::Date {
228 days_since_epoch: decode_msgpack(payload, "date")?,
229 })),
230 TAG_LOCALTIME => Ok(Value::Temporal(crate::value::TemporalValue::LocalTime {
231 nanos_since_midnight: decode_msgpack(payload, "localtime")?,
232 })),
233 TAG_TIME => {
234 let tp: TimePayload = decode_msgpack(payload, "time")?;
235 Ok(Value::Temporal(crate::value::TemporalValue::Time {
236 nanos_since_midnight: tp.nanos,
237 offset_seconds: tp.offset,
238 }))
239 }
240 TAG_LOCALDATETIME => Ok(Value::Temporal(
241 crate::value::TemporalValue::LocalDateTime {
242 nanos_since_epoch: decode_msgpack(payload, "localdatetime")?,
243 },
244 )),
245 TAG_DATETIME => {
246 let dp: DateTimePayload = decode_msgpack(payload, "datetime")?;
247 Ok(Value::Temporal(crate::value::TemporalValue::DateTime {
248 nanos_since_epoch: dp.nanos,
249 offset_seconds: dp.offset,
250 timezone_name: dp.tz_name,
251 }))
252 }
253 TAG_DURATION => {
254 let dp: DurationPayload = decode_msgpack(payload, "duration")?;
255 Ok(Value::Temporal(crate::value::TemporalValue::Duration {
256 months: dp.months,
257 days: dp.days,
258 nanos: dp.nanos,
259 }))
260 }
261 TAG_BTIC => {
262 let btic = uni_btic::encode::decode_slice(payload).map_err(|e| UniError::Storage {
263 message: format!("failed to decode BTIC: {e}"),
264 source: None,
265 })?;
266 Ok(Value::Temporal(crate::value::TemporalValue::Btic {
267 lo: btic.lo(),
268 hi: btic.hi(),
269 meta: btic.meta(),
270 }))
271 }
272 TAG_SPARSE_VECTOR => {
273 let sv = uni_sparse_vector::encode::decode_slice(payload).map_err(|e| {
274 UniError::Storage {
275 message: format!("failed to decode SparseVector: {e}"),
276 source: None,
277 }
278 })?;
279 let (indices, values) = sv.into_parts();
280 Ok(Value::SparseVector { indices, values })
281 }
282 _ => Err(UniError::Storage {
283 message: format!("unknown CypherValue tag: {tag}"),
284 source: None,
285 }),
286 }
287}
288
289pub fn peek_tag(bytes: &[u8]) -> Option<u8> {
295 bytes.first().copied()
296}
297
298pub fn is_null(bytes: &[u8]) -> bool {
300 peek_tag(bytes) == Some(TAG_NULL)
301}
302
303pub fn decode_int(bytes: &[u8]) -> Option<i64> {
309 if bytes.first().copied() != Some(TAG_INT) {
310 return None;
311 }
312 rmp_serde::from_slice(&bytes[1..]).ok()
313}
314
315pub fn decode_float(bytes: &[u8]) -> Option<f64> {
317 if bytes.first().copied() != Some(TAG_FLOAT) {
318 return None;
319 }
320 rmp_serde::from_slice(&bytes[1..]).ok()
321}
322
323pub fn decode_bool(bytes: &[u8]) -> Option<bool> {
325 if bytes.first().copied() != Some(TAG_BOOL) {
326 return None;
327 }
328 rmp_serde::from_slice(&bytes[1..]).ok()
329}
330
331pub fn decode_string(bytes: &[u8]) -> Option<String> {
333 if bytes.first().copied() != Some(TAG_STRING) {
334 return None;
335 }
336 rmp_serde::from_slice(&bytes[1..]).ok()
337}
338
339pub fn encode_int(value: i64) -> Vec<u8> {
345 let mut buf = Vec::new();
346 buf.push(TAG_INT);
347 rmp_serde::encode::write(&mut buf, &value).expect("int encode failed");
348 buf
349}
350
351pub fn encode_float(value: f64) -> Vec<u8> {
353 let mut buf = Vec::new();
354 buf.push(TAG_FLOAT);
355 rmp_serde::encode::write(&mut buf, &value).expect("float encode failed");
356 buf
357}
358
359pub fn encode_bool(value: bool) -> Vec<u8> {
361 let mut buf = Vec::new();
362 buf.push(TAG_BOOL);
363 rmp_serde::encode::write(&mut buf, &value).expect("bool encode failed");
364 buf
365}
366
367pub fn encode_string(value: &str) -> Vec<u8> {
369 let mut buf = Vec::new();
370 buf.push(TAG_STRING);
371 rmp_serde::encode::write(&mut buf, value).expect("string encode failed");
372 buf
373}
374
375pub fn encode_null() -> Vec<u8> {
377 vec![TAG_NULL]
378}
379
380pub fn extract_map_entry_raw(blob: &[u8], key: &str) -> Option<Vec<u8>> {
390 if blob.first().copied() != Some(TAG_MAP) {
391 return None;
392 }
393 let payload = &blob[1..];
394 let blob_map: HashMap<String, Vec<u8>> = rmp_serde::from_slice(payload).ok()?;
395 blob_map.get(key).cloned()
396}
397
398fn encode_to_buf(value: &Value, buf: &mut Vec<u8>) {
403 match value {
404 Value::Null => buf.push(TAG_NULL),
405 Value::Bool(b) => encode_msgpack(buf, TAG_BOOL, b, "bool"),
406 Value::Int(i) => encode_msgpack(buf, TAG_INT, i, "int"),
407 Value::Float(f) => encode_msgpack(buf, TAG_FLOAT, f, "float"),
408 Value::String(s) => encode_msgpack(buf, TAG_STRING, s, "string"),
409 Value::Bytes(b) => encode_msgpack(buf, TAG_BYTES, b, "bytes"),
410 Value::List(items) => {
411 let blobs: Vec<Vec<u8>> = items.iter().map(encode).collect();
412 encode_msgpack(buf, TAG_LIST, &blobs, "list");
413 }
414 Value::Map(map) => {
415 let blob_map: BTreeMap<String, Vec<u8>> =
416 map.iter().map(|(k, v)| (k.clone(), encode(v))).collect();
417 encode_msgpack(buf, TAG_MAP, &blob_map, "map");
418 }
419 Value::Node(node) => {
420 let mut props_blobs: Vec<(String, Vec<u8>)> = node
421 .properties
422 .iter()
423 .map(|(k, v)| (k.clone(), encode(v)))
424 .collect();
425 props_blobs.sort_by(|a, b| a.0.cmp(&b.0));
426 let payload = NodePayload {
427 vid: node.vid,
428 labels: node.labels.clone(),
429 properties: props_blobs,
430 };
431 encode_msgpack(buf, TAG_NODE, &payload, "node");
432 }
433 Value::Edge(edge) => {
434 let mut props_blobs: Vec<(String, Vec<u8>)> = edge
435 .properties
436 .iter()
437 .map(|(k, v)| (k.clone(), encode(v)))
438 .collect();
439 props_blobs.sort_by(|a, b| a.0.cmp(&b.0));
440 let payload = EdgePayload {
441 eid: edge.eid,
442 edge_type: edge.edge_type.clone(),
443 src: edge.src,
444 dst: edge.dst,
445 properties: props_blobs,
446 };
447 encode_msgpack(buf, TAG_EDGE, &payload, "edge");
448 }
449 Value::Path(path) => {
450 let payload = PathPayload {
451 nodes: path
452 .nodes
453 .iter()
454 .map(|n| encode(&Value::Node(n.clone())))
455 .collect(),
456 edges: path
457 .edges
458 .iter()
459 .map(|e| encode(&Value::Edge(e.clone())))
460 .collect(),
461 };
462 encode_msgpack(buf, TAG_PATH, &payload, "path");
463 }
464 Value::Vector(v) => encode_msgpack(buf, TAG_VECTOR, v, "vector"),
465 Value::BinaryVector(b) => encode_msgpack(buf, TAG_BINARY_VECTOR, b, "binary vector"),
466 Value::SparseVector { indices, values } => {
467 buf.push(TAG_SPARSE_VECTOR);
468 let sv = canonical_sparse_vector(indices, values);
476 buf.extend_from_slice(&uni_sparse_vector::encode::encode(&sv));
477 }
478 Value::Temporal(t) => match t {
479 crate::value::TemporalValue::Date { days_since_epoch } => {
480 encode_msgpack(buf, TAG_DATE, days_since_epoch, "date");
481 }
482 crate::value::TemporalValue::LocalTime {
483 nanos_since_midnight,
484 } => encode_msgpack(buf, TAG_LOCALTIME, nanos_since_midnight, "localtime"),
485 crate::value::TemporalValue::Time {
486 nanos_since_midnight,
487 offset_seconds,
488 } => {
489 let payload = TimePayload {
490 nanos: *nanos_since_midnight,
491 offset: *offset_seconds,
492 };
493 encode_msgpack(buf, TAG_TIME, &payload, "time");
494 }
495 crate::value::TemporalValue::LocalDateTime { nanos_since_epoch } => {
496 encode_msgpack(buf, TAG_LOCALDATETIME, nanos_since_epoch, "localdatetime");
497 }
498 crate::value::TemporalValue::DateTime {
499 nanos_since_epoch,
500 offset_seconds,
501 timezone_name,
502 } => {
503 let payload = DateTimePayload {
504 nanos: *nanos_since_epoch,
505 offset: *offset_seconds,
506 tz_name: timezone_name.clone(),
507 };
508 encode_msgpack(buf, TAG_DATETIME, &payload, "datetime");
509 }
510 crate::value::TemporalValue::Duration {
511 months,
512 days,
513 nanos,
514 } => {
515 let payload = DurationPayload {
516 months: *months,
517 days: *days,
518 nanos: *nanos,
519 };
520 encode_msgpack(buf, TAG_DURATION, &payload, "duration");
521 }
522 crate::value::TemporalValue::Btic { lo, hi, meta } => {
523 buf.push(TAG_BTIC);
524 let btic = uni_btic::Btic::new(*lo, *hi, *meta).expect("invalid BTIC value");
525 buf.extend_from_slice(&uni_btic::encode::encode(&btic));
526 }
527 },
528 }
529}
530
531#[derive(Serialize, Deserialize)]
536struct NodePayload {
537 vid: Vid,
538 labels: Vec<String>,
539 properties: Vec<(String, Vec<u8>)>,
540}
541
542#[derive(Serialize, Deserialize)]
543struct EdgePayload {
544 eid: Eid,
545 edge_type: String,
546 src: Vid,
547 dst: Vid,
548 properties: Vec<(String, Vec<u8>)>,
549}
550
551#[derive(Serialize, Deserialize)]
552struct PathPayload {
553 nodes: Vec<Vec<u8>>,
554 edges: Vec<Vec<u8>>,
555}
556
557#[derive(Serialize, Deserialize)]
558struct TimePayload {
559 nanos: i64,
560 offset: i32,
561}
562
563#[derive(Serialize, Deserialize)]
564struct DateTimePayload {
565 nanos: i64,
566 offset: i32,
567 tz_name: Option<String>,
568}
569
570#[derive(Serialize, Deserialize)]
571struct DurationPayload {
572 months: i64,
573 days: i64,
574 nanos: i64,
575}
576
577#[cfg(test)]
582mod tests {
583 use super::*;
584
585 #[test]
586 fn test_round_trip_null() {
587 let v = Value::Null;
588 let bytes = encode(&v);
589 assert_eq!(bytes[0], TAG_NULL);
590 assert_eq!(bytes.len(), 1);
591 let decoded = decode(&bytes).unwrap();
592 assert_eq!(decoded, v);
593 }
594
595 #[test]
596 fn test_round_trip_bool() {
597 for b in [true, false] {
598 let v = Value::Bool(b);
599 let bytes = encode(&v);
600 assert_eq!(bytes[0], TAG_BOOL);
601 let decoded = decode(&bytes).unwrap();
602 assert_eq!(decoded, v);
603 }
604 }
605
606 #[test]
607 fn test_round_trip_int() {
608 for i in [-100, 0, 42, i64::MAX, i64::MIN] {
609 let v = Value::Int(i);
610 let bytes = encode(&v);
611 assert_eq!(bytes[0], TAG_INT);
612 let decoded = decode(&bytes).unwrap();
613 assert_eq!(decoded, v);
614 }
615 }
616
617 #[test]
618 fn test_round_trip_float() {
619 for f in [-3.15, 0.0, 42.5, f64::MAX, f64::MIN] {
620 let v = Value::Float(f);
621 let bytes = encode(&v);
622 assert_eq!(bytes[0], TAG_FLOAT);
623 let decoded = decode(&bytes).unwrap();
624 assert_eq!(decoded, v);
625 }
626 }
627
628 #[test]
629 fn test_round_trip_string() {
630 for s in ["", "hello", "unicode: 🦀"] {
631 let v = Value::String(s.to_string());
632 let bytes = encode(&v);
633 assert_eq!(bytes[0], TAG_STRING);
634 let decoded = decode(&bytes).unwrap();
635 assert_eq!(decoded, v);
636 }
637 }
638
639 #[test]
640 fn test_round_trip_bytes() {
641 let v = Value::Bytes(vec![1, 2, 3, 255]);
642 let bytes = encode(&v);
643 assert_eq!(bytes[0], TAG_BYTES);
644 let decoded = decode(&bytes).unwrap();
645 assert_eq!(decoded, v);
646 }
647
648 #[test]
649 fn test_round_trip_list() {
650 let v = Value::List(vec![
651 Value::Int(1),
652 Value::String("two".to_string()),
653 Value::Float(3.0),
654 Value::Null,
655 ]);
656 let bytes = encode(&v);
657 assert_eq!(bytes[0], TAG_LIST);
658 let decoded = decode(&bytes).unwrap();
659 assert_eq!(decoded, v);
660 }
661
662 #[test]
663 fn test_round_trip_nested_list() {
664 let v = Value::List(vec![
665 Value::Int(1),
666 Value::List(vec![
667 Value::String("nested".to_string()),
668 Value::List(vec![Value::Bool(true)]),
669 ]),
670 ]);
671 let bytes = encode(&v);
672 let decoded = decode(&bytes).unwrap();
673 assert_eq!(decoded, v);
674 }
675
676 #[test]
677 fn test_round_trip_map() {
678 let mut map = HashMap::new();
679 map.insert("a".to_string(), Value::Int(1));
680 map.insert("b".to_string(), Value::String("two".to_string()));
681 map.insert("c".to_string(), Value::Null);
682 let v = Value::Map(map);
683 let bytes = encode(&v);
684 assert_eq!(bytes[0], TAG_MAP);
685 let decoded = decode(&bytes).unwrap();
686 assert_eq!(decoded, v);
687 }
688
689 #[test]
690 fn test_round_trip_node() {
691 let mut props = HashMap::new();
692 props.insert("name".to_string(), Value::String("Alice".to_string()));
693 props.insert("age".to_string(), Value::Int(30));
694 let v = Value::Node(Node {
695 vid: Vid::from(123),
696 labels: vec!["Person".to_string()],
697 properties: props,
698 });
699 let bytes = encode(&v);
700 assert_eq!(bytes[0], TAG_NODE);
701 let decoded = decode(&bytes).unwrap();
702 assert_eq!(decoded, v);
703 }
704
705 #[test]
706 fn test_round_trip_edge() {
707 let mut props = HashMap::new();
708 props.insert("since".to_string(), Value::Int(2020));
709 let v = Value::Edge(Edge {
710 eid: Eid::from(456),
711 edge_type: "KNOWS".to_string(),
712 src: Vid::from(1),
713 dst: Vid::from(2),
714 properties: props,
715 });
716 let bytes = encode(&v);
717 assert_eq!(bytes[0], TAG_EDGE);
718 let decoded = decode(&bytes).unwrap();
719 assert_eq!(decoded, v);
720 }
721
722 #[test]
723 fn test_round_trip_path() {
724 let v = Value::Path(Path {
725 nodes: vec![Node {
726 vid: Vid::from(1),
727 labels: vec!["A".to_string()],
728 properties: HashMap::new(),
729 }],
730 edges: vec![Edge {
731 eid: Eid::from(1),
732 edge_type: "REL".to_string(),
733 src: Vid::from(1),
734 dst: Vid::from(2),
735 properties: HashMap::new(),
736 }],
737 });
738 let bytes = encode(&v);
739 assert_eq!(bytes[0], TAG_PATH);
740 let decoded = decode(&bytes).unwrap();
741 assert_eq!(decoded, v);
742 }
743
744 #[test]
745 fn test_round_trip_vector() {
746 let v = Value::Vector(vec![0.1, 0.2, 0.3]);
747 let bytes = encode(&v);
748 assert_eq!(bytes[0], TAG_VECTOR);
749 let decoded = decode(&bytes).unwrap();
750 assert_eq!(decoded, v);
751 }
752
753 #[test]
754 fn test_round_trip_binary_vector() {
755 let v = Value::BinaryVector(vec![0x00, 0xFF, 0xA5, 0x3C]);
756 let bytes = encode(&v);
757 assert_eq!(bytes[0], TAG_BINARY_VECTOR);
758 let decoded = decode(&bytes).unwrap();
759 assert_eq!(decoded, v);
760 }
761
762 #[test]
763 fn test_round_trip_sparse_vector() {
764 let v = Value::SparseVector {
765 indices: vec![1, 7, 42],
766 values: vec![0.25, -1.5, 3.0],
767 };
768 let bytes = encode(&v);
769 assert_eq!(bytes[0], TAG_SPARSE_VECTOR);
770 let decoded = decode(&bytes).unwrap();
771 assert_eq!(decoded, v);
772 }
773
774 #[test]
775 fn encode_canonicalizes_non_canonical_sparse_without_panicking() {
776 let v = Value::SparseVector {
781 indices: vec![9, 1, 9],
782 values: vec![1.0, 2.0, 0.5],
783 };
784 let bytes = encode(&v);
785 assert_eq!(bytes[0], TAG_SPARSE_VECTOR);
786 let decoded = decode(&bytes).unwrap();
787 assert_eq!(
788 decoded,
789 Value::SparseVector {
790 indices: vec![1, 9],
791 values: vec![2.0, 1.5],
792 }
793 );
794
795 let v = Value::SparseVector {
797 indices: vec![1, 5],
798 values: vec![f32::NAN, 2.0],
799 };
800 let bytes = encode(&v);
801 let decoded = decode(&bytes).unwrap();
802 assert_eq!(
803 decoded,
804 Value::SparseVector {
805 indices: vec![5],
806 values: vec![2.0],
807 }
808 );
809
810 let v = Value::SparseVector {
812 indices: vec![1, 2, 3],
813 values: vec![1.0],
814 };
815 let _ = encode(&v); }
817
818 #[test]
819 fn test_round_trip_sparse_vector_empty() {
820 let v = Value::SparseVector {
821 indices: vec![],
822 values: vec![],
823 };
824 let bytes = encode(&v);
825 assert_eq!(bytes[0], TAG_SPARSE_VECTOR);
826 assert_eq!(decode(&bytes).unwrap(), v);
827 }
828
829 #[test]
830 fn test_round_trip_sparse_vector_nested_in_map() {
831 let mut m = std::collections::HashMap::new();
834 m.insert(
835 "emb".to_string(),
836 Value::SparseVector {
837 indices: vec![3, 9],
838 values: vec![1.0, 2.0],
839 },
840 );
841 let v = Value::Map(m);
842 let bytes = encode(&v);
843 let decoded = decode(&bytes).unwrap();
844 assert_eq!(decoded, v);
845 }
846
847 #[test]
848 fn test_peek_tag() {
849 assert_eq!(peek_tag(&encode(&Value::Null)), Some(TAG_NULL));
850 assert_eq!(peek_tag(&encode(&Value::Bool(true))), Some(TAG_BOOL));
851 assert_eq!(peek_tag(&encode(&Value::Int(42))), Some(TAG_INT));
852 assert_eq!(peek_tag(&encode(&Value::Float(3.15))), Some(TAG_FLOAT));
853 assert_eq!(
854 peek_tag(&encode(&Value::String("x".to_string()))),
855 Some(TAG_STRING)
856 );
857 assert_eq!(peek_tag(&[]), None);
858 }
859
860 #[test]
861 fn test_is_null() {
862 assert!(is_null(&encode(&Value::Null)));
863 assert!(!is_null(&encode(&Value::Int(0))));
864 assert!(!is_null(&[]));
865 }
866
867 #[test]
868 fn test_fast_decode_int() {
869 let bytes = encode(&Value::Int(42));
870 assert_eq!(decode_int(&bytes), Some(42));
871 assert_eq!(decode_int(&encode(&Value::Float(42.0))), None);
872 assert_eq!(decode_int(&encode(&Value::String("42".to_string()))), None);
873 }
874
875 #[test]
876 fn test_fast_decode_float() {
877 let bytes = encode(&Value::Float(3.15));
878 assert_eq!(decode_float(&bytes), Some(3.15));
879 assert_eq!(decode_float(&encode(&Value::Int(3))), None);
880 }
881
882 #[test]
883 fn test_fast_decode_bool() {
884 let bytes = encode(&Value::Bool(true));
885 assert_eq!(decode_bool(&bytes), Some(true));
886 assert_eq!(decode_bool(&encode(&Value::Int(1))), None);
887 }
888
889 #[test]
890 fn test_fast_decode_string() {
891 let bytes = encode(&Value::String("hello".to_string()));
892 assert_eq!(decode_string(&bytes), Some("hello".to_string()));
893 assert_eq!(decode_string(&encode(&Value::Int(42))), None);
894 }
895
896 #[test]
897 fn test_int_float_distinction() {
898 let int_val = Value::Int(42);
900 let float_val = Value::Float(42.0);
901
902 let int_bytes = encode(&int_val);
903 let float_bytes = encode(&float_val);
904
905 assert_eq!(int_bytes[0], TAG_INT);
907 assert_eq!(float_bytes[0], TAG_FLOAT);
908
909 assert_ne!(int_bytes, float_bytes);
911
912 assert_eq!(decode(&int_bytes).unwrap(), Value::Int(42));
914 assert_eq!(decode(&float_bytes).unwrap(), Value::Float(42.0));
915 }
916
917 #[test]
918 fn test_round_trip_btic_epoch_instant() {
919 let v = Value::Temporal(crate::value::TemporalValue::Btic {
920 lo: 0,
921 hi: 1,
922 meta: 0x0000_0000_0000_0000,
923 });
924 let bytes = encode(&v);
925 assert_eq!(bytes[0], TAG_BTIC);
926 assert_eq!(bytes.len(), 25); let decoded = decode(&bytes).unwrap();
928 assert_eq!(decoded, v);
929 }
930
931 #[test]
932 fn test_round_trip_btic_year_1985() {
933 let meta = 0x7700_0000_0000_0000u64; let v = Value::Temporal(crate::value::TemporalValue::Btic {
935 lo: 473_385_600_000,
936 hi: 504_921_600_000,
937 meta,
938 });
939 let bytes = encode(&v);
940 assert_eq!(bytes[0], TAG_BTIC);
941 let decoded = decode(&bytes).unwrap();
942 assert_eq!(decoded, v);
943 }
944
945 #[test]
946 fn test_round_trip_btic_unbounded() {
947 let v = Value::Temporal(crate::value::TemporalValue::Btic {
948 lo: i64::MIN,
949 hi: i64::MAX,
950 meta: 0,
951 });
952 let bytes = encode(&v);
953 assert_eq!(bytes[0], TAG_BTIC);
954 let decoded = decode(&bytes).unwrap();
955 assert_eq!(decoded, v);
956 }
957
958 #[test]
959 fn test_round_trip_btic_with_certainty() {
960 let meta = 0x7750_0000_0000_0000u64; let v = Value::Temporal(crate::value::TemporalValue::Btic {
963 lo: -77_914_137_600_000, hi: -77_882_601_600_000,
965 meta,
966 });
967 let bytes = encode(&v);
968 let decoded = decode(&bytes).unwrap();
969 assert_eq!(decoded, v);
970 }
971}