everscale_types/boc/
serde.rs

1use std::borrow::Cow;
2use std::collections::{BTreeMap, HashMap};
3use std::hash::{BuildHasher, Hash};
4use std::marker::PhantomData;
5use std::rc::Rc;
6use std::sync::Arc;
7
8use serde::de::{MapAccess, Visitor};
9use serde::ser::SerializeTuple;
10use serde::{Deserialize, Deserializer, Serialize, Serializer};
11
12use crate::cell::{Cell, DynCell};
13
14// === SerdeBoc ===
15
16/// A wrapper type which implements `Serialize` and `Deserialize` for
17/// types involving `Cell`.
18#[repr(transparent)]
19pub struct SerdeBoc<T: ?Sized>(T);
20
21impl<T: ?Sized> SerdeBoc<T> {
22    /// Creates a wrapper around a reference to the value.
23    #[inline(always)]
24    pub const fn wrap(value: &T) -> &Self {
25        // SAFETY: SerdeBoc is #[repr(transparent)]
26        unsafe { &*(value as *const T as *const Self) }
27    }
28}
29
30impl<T> SerdeBoc<T> {
31    #[inline(always)]
32    const fn wrap_slice(value: &[T]) -> &[Self] {
33        // SAFETY: SerdeBoc is #[repr(transparent)]
34        unsafe { std::slice::from_raw_parts(value.as_ptr() as *const Self, value.len()) }
35    }
36
37    /// Consumes self, returning the inner value.
38    #[inline(always)]
39    pub fn into_inner(self) -> T {
40        self.0
41    }
42}
43
44impl<T> From<T> for SerdeBoc<T> {
45    #[inline]
46    fn from(val: T) -> SerdeBoc<T> {
47        Self(val)
48    }
49}
50
51impl<T: SerializeAsBoc + ?Sized> Serialize for SerdeBoc<T> {
52    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
53        self.0.serialize_as_boc(serializer)
54    }
55}
56
57impl<'de, T: DeserializeAsBoc<'de>> Deserialize<'de> for SerdeBoc<T> {
58    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
59    where
60        D: Deserializer<'de>,
61    {
62        T::deserialize_as_boc(deserializer).map(Self)
63    }
64}
65
66// === Serializer stuff ===
67
68trait SerializeAsBoc {
69    fn serialize_as_boc<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>;
70}
71
72impl SerializeAsBoc for Cell {
73    #[inline]
74    fn serialize_as_boc<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
75        self.as_ref().serialize(serializer)
76    }
77}
78
79impl SerializeAsBoc for DynCell {
80    #[inline]
81    fn serialize_as_boc<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
82        self.serialize(serializer)
83    }
84}
85
86impl<T: SerializeAsBoc + ?Sized> SerializeAsBoc for &'_ T {
87    #[inline]
88    fn serialize_as_boc<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
89        T::serialize_as_boc(self, serializer)
90    }
91}
92
93impl<T: SerializeAsBoc> SerializeAsBoc for Option<T> {
94    #[inline]
95    fn serialize_as_boc<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
96        self.as_ref().map(SerdeBoc::<T>::wrap).serialize(serializer)
97    }
98}
99
100impl<T: SerializeAsBoc + ?Sized> SerializeAsBoc for Box<T> {
101    #[inline]
102    fn serialize_as_boc<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
103        T::serialize_as_boc(self.as_ref(), serializer)
104    }
105}
106
107impl<T: SerializeAsBoc + ?Sized> SerializeAsBoc for Rc<T> {
108    #[inline]
109    fn serialize_as_boc<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
110        T::serialize_as_boc(self.as_ref(), serializer)
111    }
112}
113
114impl<T: SerializeAsBoc + ?Sized> SerializeAsBoc for Arc<T> {
115    #[inline]
116    fn serialize_as_boc<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
117        T::serialize_as_boc(self.as_ref(), serializer)
118    }
119}
120
121impl<T: SerializeAsBoc> SerializeAsBoc for [T] {
122    #[inline]
123    fn serialize_as_boc<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
124        SerdeBoc::wrap_slice(self).serialize(serializer)
125    }
126}
127
128impl<T: SerializeAsBoc> SerializeAsBoc for Vec<T> {
129    #[inline]
130    fn serialize_as_boc<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
131        self.as_slice().serialize_as_boc(serializer)
132    }
133}
134
135impl<T> SerializeAsBoc for [T; 0] {
136    #[inline]
137    fn serialize_as_boc<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
138        ok!(serializer.serialize_tuple(0)).end()
139    }
140}
141
142macro_rules! serialize_as_boc_array_impls {
143    ($($len:tt)+) => {
144        $(
145            #[allow(clippy::zero_prefixed_literal)]
146            impl<T: SerializeAsBoc> SerializeAsBoc for [T; $len] {
147                #[inline]
148                fn serialize_as_boc<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
149                where
150                    S: Serializer,
151                {
152                    let mut seq = ok!(serializer.serialize_tuple($len));
153                    for e in self {
154                        ok!(seq.serialize_element(SerdeBoc::<T>::wrap(e)));
155                    }
156                    seq.end()
157                }
158            }
159        )+
160    }
161}
162
163serialize_as_boc_array_impls! {
164    01 02 03 04 05 06 07 08 09 10
165    11 12 13 14 15 16 17 18 19 20
166    21 22 23 24 25 26 27 28 29 30
167    31 32
168}
169
170macro_rules! serialize_as_boc_map_impl {
171    ($ty:ident<K$(: $kbound1:ident $(+ $kbound2:ident)*)*, V$(, $typaram:ident: $bound:ident)*>) => {
172        impl<K, V$(, $typaram)*> SerializeAsBoc for $ty<K, V$(, $typaram)*>
173        where
174            K: Serialize $(+ $kbound1 $(+ $kbound2)*)*,
175            V: SerializeAsBoc,
176            $($typaram: $bound,)*
177        {
178            #[inline]
179            fn serialize_as_boc<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
180            where
181                S: Serializer,
182            {
183                serializer.collect_map(self.iter().map(|(k, v)| (k, SerdeBoc::wrap(v))))
184            }
185        }
186    }
187}
188
189serialize_as_boc_map_impl! { BTreeMap<K: Ord, V> }
190serialize_as_boc_map_impl! { HashMap<K: Eq + Hash, V, H: BuildHasher> }
191
192// === Deserializer stuff ===
193
194trait DeserializeAsBoc<'de>: Sized {
195    fn deserialize_as_boc<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>;
196}
197
198impl<'de> DeserializeAsBoc<'de> for Cell {
199    fn deserialize_as_boc<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
200        use serde::de::Error;
201
202        let is_human_readable = deserializer.is_human_readable();
203        let mut boc = ok!(borrow_cow_bytes(deserializer));
204
205        if is_human_readable {
206            match crate::util::decode_base64(boc) {
207                Ok(bytes) => {
208                    boc = Cow::Owned(bytes);
209                }
210                Err(_) => return Err(Error::custom("invalid base64 string")),
211            }
212        }
213
214        match crate::boc::Boc::decode(boc) {
215            Ok(cell) => Ok(cell),
216            Err(e) => Err(Error::custom(e)),
217        }
218    }
219}
220
221impl<'de, T: DeserializeAsBoc<'de>> DeserializeAsBoc<'de> for Box<T> {
222    #[inline]
223    fn deserialize_as_boc<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
224        let value = ok!(Box::<SerdeBoc<T>>::deserialize(deserializer));
225        // SAFETY: `SerdeBoc<T>` has the same layout as `T`.
226        Ok(unsafe { Box::from_raw(Box::into_raw(value).cast::<T>()) })
227    }
228}
229
230impl<'de, T: DeserializeAsBoc<'de>> DeserializeAsBoc<'de> for Option<T> {
231    #[inline]
232    fn deserialize_as_boc<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
233        Ok(ok!(Option::<SerdeBoc<T>>::deserialize(deserializer)).map(SerdeBoc::into_inner))
234    }
235}
236
237impl<'de, T: DeserializeAsBoc<'de>> DeserializeAsBoc<'de> for Vec<T> {
238    #[inline]
239    fn deserialize_as_boc<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
240        Ok(ok!(Vec::<SerdeBoc<T>>::deserialize(deserializer))
241            .into_iter()
242            .map(SerdeBoc::into_inner)
243            .collect())
244    }
245}
246
247impl<'de, T: DeserializeAsBoc<'de>, const N: usize> DeserializeAsBoc<'de> for [T; N]
248where
249    [SerdeBoc<T>; N]: Deserialize<'de>,
250{
251    fn deserialize_as_boc<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
252        let value = ok!(<[SerdeBoc<T>; N]>::deserialize(deserializer));
253        Ok(value.map(SerdeBoc::into_inner))
254    }
255}
256
257macro_rules! deserialize_as_boc_map_impl {
258    (
259        $ty:ident <K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)*)*>,
260        $access:ident,
261        $with_capacity:expr,
262    ) => {
263        impl<'de, K, V $(, $typaram)*> DeserializeAsBoc<'de> for $ty<K, V $(, $typaram)*>
264        where
265            K: Deserialize<'de> $(+ $kbound1 $(+ $kbound2)*)*,
266            V: DeserializeAsBoc<'de>,
267            $($typaram: $bound1 $(+ $bound2)*),*
268        {
269            fn deserialize_as_boc<D>(deserializer: D) -> Result<Self, D::Error>
270            where
271                D: Deserializer<'de>,
272            {
273                struct MapVisitor<K, V $(, $typaram)*> {
274                    marker: PhantomData<$ty<K, V $(, $typaram)*>>,
275                }
276
277                impl<'de, K, V $(, $typaram)*> Visitor<'de> for MapVisitor<K, V $(, $typaram)*>
278                where
279                    K: Deserialize<'de> $(+ $kbound1 $(+ $kbound2)*)*,
280                    V: DeserializeAsBoc<'de>,
281                    $($typaram: $bound1 $(+ $bound2)*),*
282                {
283                    type Value = $ty<K, V $(, $typaram)*>;
284
285                    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
286                        formatter.write_str("a map")
287                    }
288
289                    #[inline]
290                    fn visit_map<A>(self, mut $access: A) -> Result<Self::Value, A::Error>
291                    where
292                        A: MapAccess<'de>,
293                    {
294                        let mut values = $with_capacity;
295
296                        while let Some((key, SerdeBoc(value))) = ok!($access.next_entry()) {
297                            values.insert(key, value);
298                        }
299
300                        Ok(values)
301                    }
302                }
303
304                let visitor = MapVisitor { marker: PhantomData };
305                deserializer.deserialize_map(visitor)
306            }
307        }
308    }
309}
310
311deserialize_as_boc_map_impl! {
312    BTreeMap<K: Ord, V>,
313    map,
314    BTreeMap::new(),
315}
316
317deserialize_as_boc_map_impl! {
318    HashMap<K: Eq + Hash, V, S: BuildHasher + Default>,
319    map,
320    HashMap::with_capacity_and_hasher(cautious_size_hint::<(K, V)>(map.size_hint()), S::default()),
321}
322
323fn cautious_size_hint<Element>(hint: Option<usize>) -> usize {
324    const MAX_PREALLOC_BYTES: usize = 1024 * 1024;
325
326    if std::mem::size_of::<Element>() == 0 {
327        0
328    } else {
329        std::cmp::min(
330            hint.unwrap_or(0),
331            MAX_PREALLOC_BYTES / std::mem::size_of::<Element>(),
332        )
333    }
334}
335
336// === Other stuff ===
337
338fn borrow_cow_bytes<'de: 'a, 'a, D>(deserializer: D) -> Result<std::borrow::Cow<'a, [u8]>, D::Error>
339where
340    D: Deserializer<'de>,
341{
342    use serde::de::Error;
343
344    struct CowBytesVisitor;
345
346    impl<'a> Visitor<'a> for CowBytesVisitor {
347        type Value = Cow<'a, [u8]>;
348
349        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
350            formatter.write_str("a byte array")
351        }
352
353        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
354        where
355            E: Error,
356        {
357            Ok(Cow::Owned(v.as_bytes().to_vec()))
358        }
359
360        fn visit_borrowed_str<E>(self, v: &'a str) -> Result<Self::Value, E>
361        where
362            E: Error,
363        {
364            Ok(Cow::Borrowed(v.as_bytes()))
365        }
366
367        fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
368        where
369            E: Error,
370        {
371            Ok(Cow::Owned(v.into_bytes()))
372        }
373
374        fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
375        where
376            E: Error,
377        {
378            Ok(Cow::Owned(v.to_vec()))
379        }
380
381        fn visit_borrowed_bytes<E>(self, v: &'a [u8]) -> Result<Self::Value, E>
382        where
383            E: Error,
384        {
385            Ok(Cow::Borrowed(v))
386        }
387
388        fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
389        where
390            E: Error,
391        {
392            Ok(Cow::Owned(v))
393        }
394    }
395
396    deserializer.deserialize_bytes(CowBytesVisitor)
397}
398
399#[cfg(test)]
400mod tests {
401    use crate::cell::CellFamily;
402
403    use super::*;
404
405    #[derive(serde::Serialize)]
406    struct StructWithDynCell<'a> {
407        #[serde(with = "crate::boc::Boc")]
408        cell: &'a DynCell,
409    }
410
411    #[test]
412    fn serde_dyn_cell_works() {
413        serde_json::to_string(&StructWithDynCell {
414            cell: Cell::empty_cell_ref(),
415        })
416        .unwrap();
417    }
418}