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