canic_core/cdk/
serialize.rs1use serde::{Serialize, de::DeserializeOwned};
8use thiserror::Error as ThisError;
9
10#[derive(Debug, ThisError)]
17pub enum SerializeError {
18 #[error("serialize error: {0}")]
19 Serialize(String),
20
21 #[error("deserialize error: {0}")]
22 Deserialize(String),
23}
24
25pub fn serialize<T>(value: &T) -> Result<Vec<u8>, SerializeError>
27where
28 T: Serialize,
29{
30 let mut bytes = Vec::new();
31 ciborium::ser::into_writer(value, &mut bytes)
32 .map_err(|err| SerializeError::Serialize(err.to_string()))?;
33 Ok(bytes)
34}
35
36pub fn deserialize<T>(bytes: &[u8]) -> Result<T, SerializeError>
38where
39 T: DeserializeOwned,
40{
41 ciborium::de::from_reader(bytes).map_err(|err| SerializeError::Deserialize(err.to_string()))
42}
43
44#[cfg(test)]
45mod tests {
46 use super::{deserialize, serialize};
47 use serde::{Deserialize, Serialize};
48 use std::collections::BTreeMap;
49
50 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
51 enum FixtureVariant {
52 Unit,
53 Tuple(u32, String),
54 Struct { enabled: bool },
55 }
56
57 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
58 struct StableShapeFixture {
59 flag: bool,
60 count: u64,
61 signed: i64,
62 text: String,
63 #[serde(with = "serde_bytes")]
64 bytes: Vec<u8>,
65 array: [u8; 3],
66 values: Vec<u16>,
67 present: Option<u32>,
68 absent: Option<u32>,
69 variants: Vec<FixtureVariant>,
70 labels: BTreeMap<String, u64>,
71 }
72
73 #[test]
74 fn stable_serde_shape_has_exact_cbor_bytes() {
75 let fixture = StableShapeFixture {
76 flag: true,
77 count: 42,
78 signed: -7,
79 text: "canic".to_string(),
80 bytes: vec![0, 1, 255],
81 array: [2, 3, 4],
82 values: vec![5, 256],
83 present: Some(9),
84 absent: None,
85 variants: vec![
86 FixtureVariant::Unit,
87 FixtureVariant::Tuple(10, "ten".to_string()),
88 FixtureVariant::Struct { enabled: false },
89 ],
90 labels: BTreeMap::from([("a".to_string(), 1), ("b".to_string(), 2)]),
91 };
92 let bytes = serialize(&fixture).expect("serialize stable shape fixture");
93
94 assert_eq!(
95 bytes,
96 hex_fixture(
97 "ab64666c6167f565636f756e74182a667369676e65642664746578746563616e6963656279746573430001ff656172726179830203046676616c75657382051901006770726573656e740966616273656e74f66876617269616e74738364556e6974a1655475706c65820a6374656ea166537472756374a167656e61626c6564f4666c6162656c73a2616101616202"
98 )
99 );
100 assert_eq!(
101 deserialize::<StableShapeFixture>(&bytes).expect("deserialize stable shape fixture"),
102 fixture
103 );
104 }
105
106 fn hex_fixture(hex: &str) -> Vec<u8> {
107 hex.as_bytes()
108 .chunks_exact(2)
109 .map(|pair| {
110 let pair = std::str::from_utf8(pair).expect("fixture hex is UTF-8");
111 u8::from_str_radix(pair, 16).expect("fixture hex byte is valid")
112 })
113 .collect()
114 }
115}