ic_stable_memory/encoding/
dyn_size.rs

1use candid::de::IDLDeserialize;
2use candid::utils::ArgumentDecoder;
3use candid::{CandidType, Deserialize, Result};
4
5/// Trait allowing encoding and decoding of unsized data.
6///
7/// See also [SBox].
8///
9/// By default is implemented for:
10/// 1. Every [AsFixedSizeBytes] type
11/// 2. `Vec<u8>`
12/// 3. `String`
13///
14/// This trait can be easily implemented using derive macros:
15/// 1. [derive::CandidAsDynSizeBytes] implements this trait for types which
16/// already implement [candid::CandidType] and [candid::Deserialize].
17/// 2. [derive::FixedSizeAsDynSizeBytes] implements this trait for types which already
18/// implement [AsFixedSizeBytes].
19pub trait AsDynSizeBytes {
20    /// Encodes self into vector of bytes
21    ///
22    /// # Panics
23    /// Should panic if data encoding failed.
24    fn as_dyn_size_bytes(&self) -> Vec<u8>;
25
26    /// Decodes self from a slice of bytes.
27    ///
28    /// # Important
29    /// The slice *can* have trailing bytes with unmeaningful.
30    /// It means, that if your data encoded value is [1, 0, 1, 0], then it should also be able to
31    /// decode itself from a slice like [1, 0, 1, 0, 0, 0, 0, 0, 0] or [1, 0, 1, 0, 1, 1, 0, 1].
32    ///
33    /// # Panics
34    /// Should panic if data decoding failed.
35    fn from_dyn_size_bytes(buf: &[u8]) -> Self;
36}
37
38#[cfg(not(feature = "custom_dyn_encoding"))]
39use crate::encoding::AsFixedSizeBytes;
40
41#[cfg(not(feature = "custom_dyn_encoding"))]
42use crate::primitive::s_box::SBox;
43
44#[cfg(not(feature = "custom_dyn_encoding"))]
45impl<T: AsFixedSizeBytes> AsDynSizeBytes for T {
46    #[inline]
47    fn as_dyn_size_bytes(&self) -> Vec<u8> {
48        let mut v = vec![0u8; T::SIZE];
49        self.as_fixed_size_bytes(&mut v);
50
51        v
52    }
53
54    #[inline]
55    fn from_dyn_size_bytes(buf: &[u8]) -> Self {
56        Self::from_fixed_size_bytes(&buf[0..T::SIZE])
57    }
58}
59
60#[cfg(not(feature = "custom_dyn_encoding"))]
61impl AsDynSizeBytes for Vec<u8> {
62    #[inline]
63    fn as_dyn_size_bytes(&self) -> Vec<u8> {
64        let mut v = vec![0u8; usize::SIZE + self.len()];
65
66        self.len().as_fixed_size_bytes(&mut v[0..usize::SIZE]);
67        v[usize::SIZE..(usize::SIZE + self.len())].copy_from_slice(&self);
68
69        v
70    }
71
72    #[inline]
73    fn from_dyn_size_bytes(buf: &[u8]) -> Self {
74        let len = usize::from_fixed_size_bytes(&buf[0..usize::SIZE]);
75        let mut v = vec![0u8; len];
76
77        v.copy_from_slice(&buf[usize::SIZE..(usize::SIZE + len)]);
78
79        v
80    }
81}
82
83#[cfg(not(feature = "custom_dyn_encoding"))]
84impl AsDynSizeBytes for String {
85    #[inline]
86    fn as_dyn_size_bytes(&self) -> Vec<u8> {
87        let mut v = vec![0u8; usize::SIZE + self.len()];
88
89        self.len().as_fixed_size_bytes(&mut v[0..usize::SIZE]);
90        v[usize::SIZE..(usize::SIZE + self.len())].copy_from_slice(self.as_bytes());
91
92        v
93    }
94
95    #[inline]
96    fn from_dyn_size_bytes(buf: &[u8]) -> Self {
97        let len = usize::from_fixed_size_bytes(&buf[0..usize::SIZE]);
98        let mut v = vec![0u8; len];
99
100        v.copy_from_slice(&buf[usize::SIZE..(usize::SIZE + len)]);
101
102        String::from_utf8(v).unwrap()
103    }
104}
105
106pub fn candid_decode_args_allow_trailing<'a, Tuple>(bytes: &'a [u8]) -> Result<Tuple>
107where
108    Tuple: ArgumentDecoder<'a>,
109{
110    let mut de = IDLDeserialize::new(bytes)?;
111    let res = ArgumentDecoder::decode(&mut de)?;
112
113    Ok(res)
114}
115
116pub fn candid_decode_one_allow_trailing<'a, T>(bytes: &'a [u8]) -> Result<T>
117where
118    T: Deserialize<'a> + CandidType,
119{
120    let (res,) = candid_decode_args_allow_trailing(bytes)?;
121    Ok(res)
122}