holo_hash/
ser.rs

1//! Defines the serialization rules for HoloHashes
2
3use crate::HashType;
4use crate::HoloHash;
5use holochain_serialized_bytes::SerializedBytes;
6use holochain_serialized_bytes::SerializedBytesError;
7use holochain_serialized_bytes::UnsafeBytes;
8
9impl<T: HashType> serde::Serialize for HoloHash<T> {
10    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
11    where
12        S: serde::Serializer,
13    {
14        serializer.serialize_bytes(self.get_raw_39())
15    }
16}
17
18impl<'de, T: HashType> serde::Deserialize<'de> for HoloHash<T> {
19    fn deserialize<D>(deserializer: D) -> Result<HoloHash<T>, D::Error>
20    where
21        D: serde::Deserializer<'de>,
22    {
23        deserializer.deserialize_bytes(HoloHashVisitor(std::marker::PhantomData))
24    }
25}
26
27struct HoloHashVisitor<T: HashType>(std::marker::PhantomData<T>);
28
29impl<'de, T: HashType> serde::de::Visitor<'de> for HoloHashVisitor<T> {
30    type Value = HoloHash<T>;
31
32    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
33        formatter.write_str("a HoloHash of primitive hash_type")
34    }
35
36    fn visit_bytes<E>(self, h: &[u8]) -> Result<Self::Value, E>
37    where
38        E: serde::de::Error,
39    {
40        if !h.len() == 39 {
41            Err(serde::de::Error::custom(
42                "HoloHash serialized representation must be exactly 39 bytes",
43            ))
44        } else {
45            HoloHash::try_from_raw_39(h.to_vec())
46                .map_err(|e| serde::de::Error::custom(format!("HoloHash error: {:?}", e)))
47        }
48    }
49
50    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
51    where
52        A: serde::de::SeqAccess<'de>,
53    {
54        let mut vec = Vec::with_capacity(seq.size_hint().unwrap_or(0));
55
56        while let Some(b) = seq.next_element()? {
57            vec.push(b);
58        }
59
60        self.visit_bytes(&vec)
61    }
62
63    #[cfg(feature = "encoding")]
64    fn visit_str<E>(self, b64: &str) -> Result<Self::Value, E>
65    where
66        E: serde::de::Error,
67    {
68        let h = crate::holo_hash_decode_unchecked(b64)
69            .map_err(|e| serde::de::Error::custom(format!("HoloHash error: {:?}", e)))?;
70        if !h.len() == 39 {
71            Err(serde::de::Error::custom(
72                "HoloHash serialized representation must be exactly 39 bytes",
73            ))
74        } else {
75            HoloHash::try_from_raw_39(h.to_vec())
76                .map_err(|e| serde::de::Error::custom(format!("HoloHash error: {:?}", e)))
77        }
78    }
79}
80
81impl<T: HashType> std::convert::TryFrom<&HoloHash<T>> for SerializedBytes {
82    type Error = SerializedBytesError;
83    fn try_from(t: &HoloHash<T>) -> std::result::Result<SerializedBytes, SerializedBytesError> {
84        match holochain_serialized_bytes::encode(t) {
85            Ok(v) => Ok(SerializedBytes::from(UnsafeBytes::from(v))),
86            Err(e) => Err(SerializedBytesError::Serialize(e.to_string())),
87        }
88    }
89}
90
91impl<T: HashType> std::convert::TryFrom<HoloHash<T>> for SerializedBytes {
92    type Error = SerializedBytesError;
93    fn try_from(t: HoloHash<T>) -> std::result::Result<SerializedBytes, SerializedBytesError> {
94        SerializedBytes::try_from(&t)
95    }
96}
97
98impl<T: HashType> std::convert::TryFrom<SerializedBytes> for HoloHash<T> {
99    type Error = SerializedBytesError;
100    fn try_from(sb: SerializedBytes) -> std::result::Result<HoloHash<T>, SerializedBytesError> {
101        match holochain_serialized_bytes::decode(sb.bytes()) {
102            Ok(v) => Ok(v),
103            Err(e) => Err(SerializedBytesError::Deserialize(e.to_string())),
104        }
105    }
106}
107
108#[cfg(test)]
109mod tests {
110    use crate::*;
111    use holochain_serialized_bytes::prelude::*;
112    use std::convert::TryInto;
113
114    #[derive(serde::Deserialize, Debug)]
115    #[serde(transparent)]
116    struct TestByteArray(#[serde(with = "serde_bytes")] Vec<u8>);
117
118    #[test]
119    #[cfg(feature = "serialization")]
120    fn test_serialized_bytes_roundtrip() {
121        use holochain_serialized_bytes::SerializedBytes;
122        use std::convert::TryInto;
123
124        let h_orig = DnaHash::from_raw_36(vec![0xdb; HOLO_HASH_UNTYPED_LEN]);
125        let h: SerializedBytes = h_orig.clone().try_into().unwrap();
126        let h: DnaHash = h.try_into().unwrap();
127
128        assert_eq!(h_orig, h);
129        assert_eq!(*h.hash_type(), hash_type::Dna::new());
130    }
131
132    #[test]
133    fn test_rmp_roundtrip() {
134        let h_orig = AgentPubKey::from_raw_36(vec![0xdb; HOLO_HASH_UNTYPED_LEN]);
135        let buf = holochain_serialized_bytes::encode(&h_orig).unwrap();
136        let h: AgentPubKey = holochain_serialized_bytes::decode(&buf).unwrap();
137
138        assert_eq!(h_orig, h);
139        assert_eq!(*h.hash_type(), hash_type::Agent::new());
140
141        // Make sure that the representation is a raw 39-byte array
142        let array: TestByteArray = holochain_serialized_bytes::decode(&buf).unwrap();
143        assert_eq!(array.0.len(), HOLO_HASH_FULL_LEN);
144        assert_eq!(
145            array.0,
146            vec![
147                132, 32, 36, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219,
148                219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219,
149                219, 219, 219, 219, 219, 219,
150            ]
151        );
152    }
153
154    #[test]
155    fn test_json_roundtrip() {
156        let h_orig = AgentPubKey::from_raw_36(vec![0xdb; HOLO_HASH_UNTYPED_LEN]);
157        let json = serde_json::to_string(&h_orig).unwrap();
158        let h: AgentPubKey = serde_json::from_str(&json).unwrap();
159
160        assert_eq!(h_orig, h);
161        assert_eq!(*h.hash_type(), hash_type::Agent::new());
162
163        // Make sure that the representation is a raw 39-byte array
164        let array: TestByteArray = serde_json::from_str(&json).unwrap();
165        assert_eq!(array.0.len(), HOLO_HASH_FULL_LEN);
166        assert_eq!(
167            array.0,
168            vec![
169                132, 32, 36, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219,
170                219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219,
171                219, 219, 219, 219, 219, 219,
172            ]
173        );
174    }
175
176    #[test]
177    fn test_composite_hashtype_roundtrips() {
178        {
179            let h_orig = AnyDhtHash::from_raw_36_and_type(
180                vec![0xdb; HOLO_HASH_UNTYPED_LEN],
181                hash_type::AnyDht::Action,
182            );
183            let buf = holochain_serialized_bytes::encode(&h_orig).unwrap();
184            let h: AnyDhtHash = holochain_serialized_bytes::decode(&buf).unwrap();
185            assert_eq!(h_orig, h);
186            assert_eq!(*h.hash_type(), hash_type::AnyDht::Action);
187        }
188        {
189            let h_orig = AnyDhtHash::from_raw_36_and_type(
190                vec![0xdb; HOLO_HASH_UNTYPED_LEN],
191                hash_type::AnyDht::Entry,
192            );
193            let buf = holochain_serialized_bytes::encode(&h_orig).unwrap();
194            let h: AnyDhtHash = holochain_serialized_bytes::decode(&buf).unwrap();
195            assert_eq!(h_orig, h);
196            assert_eq!(*h.hash_type(), hash_type::AnyDht::Entry);
197        }
198        {
199            let h_orig = AnyDhtHash::from_raw_36_and_type(
200                vec![0xdb; HOLO_HASH_UNTYPED_LEN],
201                hash_type::AnyDht::Entry,
202            );
203            let buf = holochain_serialized_bytes::encode(&h_orig).unwrap();
204            let h: AnyDhtHash = holochain_serialized_bytes::decode(&buf).unwrap();
205            assert_eq!(h_orig, h);
206            assert_eq!(*h.hash_type(), hash_type::AnyDht::Entry);
207        }
208    }
209
210    #[test]
211    fn test_any_dht_deserialization() {
212        {
213            let h_orig = EntryHash::from_raw_36_and_type(
214                vec![0xdb; HOLO_HASH_UNTYPED_LEN],
215                hash_type::Entry,
216            );
217            let buf = holochain_serialized_bytes::encode(&h_orig).unwrap();
218            let _: AnyDhtHash = holochain_serialized_bytes::decode(&buf).unwrap();
219        }
220        {
221            let h_orig = ActionHash::from_raw_36_and_type(
222                vec![0xdb; HOLO_HASH_UNTYPED_LEN],
223                hash_type::Action,
224            );
225            let buf = holochain_serialized_bytes::encode(&h_orig).unwrap();
226            let _: AnyDhtHash = holochain_serialized_bytes::decode(&buf).unwrap();
227        }
228    }
229
230    #[test]
231    #[should_panic]
232    fn test_any_dht_deserialization_crossover_error() {
233        {
234            let h_orig = DhtOpHash::from_raw_36_and_type(
235                vec![0xdb; HOLO_HASH_UNTYPED_LEN],
236                hash_type::DhtOp,
237            );
238            let buf = holochain_serialized_bytes::encode(&h_orig).unwrap();
239            let _: AnyDhtHash = holochain_serialized_bytes::decode(&buf).unwrap();
240        }
241    }
242
243    #[test]
244    fn test_struct_to_struct_roundtrip() {
245        #[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize, SerializedBytes)]
246        struct TestData {
247            e: EntryHash,
248            h: ActionHash,
249        }
250
251        let orig = TestData {
252            e: EntryHash::from_raw_36_and_type(vec![0xdb; HOLO_HASH_UNTYPED_LEN], hash_type::Entry),
253            h: ActionHash::from_raw_36(vec![0xdb; HOLO_HASH_UNTYPED_LEN]),
254        };
255
256        let sb: SerializedBytes = (&orig).try_into().unwrap();
257        let res: TestData = sb.try_into().unwrap();
258
259        assert_eq!(orig, res);
260        assert_eq!(*orig.e.hash_type(), hash_type::Entry);
261        assert_eq!(*orig.h.hash_type(), hash_type::Action);
262    }
263
264    #[test]
265    fn test_json_to_rust() {
266        #[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize, SerializedBytes)]
267        struct Data {
268            any_hash: AnyDhtHash,
269            content: String,
270        }
271
272        let any_hash = AnyDhtHash::from_raw_36_and_type(
273            b"000000000000000000000000000000000000".to_vec(),
274            hash_type::AnyDht::Action,
275        );
276        let hash_type_sb: SerializedBytes = any_hash.hash_type().try_into().unwrap();
277        let hash_type_json = r#"{"Action":[132,41,36]}"#;
278        assert_eq!(format!("{:?}", hash_type_sb), hash_type_json.to_string());
279
280        let hash_type_from_sb: hash_type::AnyDht = hash_type_sb.try_into().unwrap();
281        assert_eq!(hash_type_from_sb, hash_type::AnyDht::Action);
282
283        let hash_type_from_json: hash_type::AnyDht = serde_json::from_str(hash_type_json).unwrap();
284        assert_eq!(hash_type_from_json, hash_type::AnyDht::Action);
285    }
286
287    #[test]
288    fn test_generic_content_roundtrip() {
289        #[derive(Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
290        struct Generic<K> {
291            bytes: Vec<u8>,
292            __marker: std::marker::PhantomData<K>,
293        }
294
295        impl<K> Generic<K>
296        where
297            K: serde::Serialize + serde::de::DeserializeOwned + std::fmt::Debug,
298            // V: Serialize + DeserializeOwned + std::fmt::Debug,
299        {
300            fn new() -> Self {
301                Self {
302                    bytes: Vec::new(),
303                    __marker: Default::default(),
304                }
305            }
306
307            fn get(&self) -> K {
308                holochain_serialized_bytes::decode(&self.bytes).unwrap()
309            }
310
311            fn put(&mut self, k: &K) {
312                self.bytes = holochain_serialized_bytes::encode(k).unwrap();
313            }
314        }
315
316        let mut g: Generic<ActionHash> = Generic::new();
317        let h = ActionHash::from_raw_36(vec![0xdb; HOLO_HASH_UNTYPED_LEN]);
318        g.put(&h);
319        assert_eq!(h, g.get());
320    }
321}