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