ic_stable_structures/storable/
tuples.rs

1use crate::storable::{
2    bounds, bytes_to_store_size, bytes_to_store_size_bounded, Bound, Bounds, Storable,
3};
4use std::borrow::Cow;
5
6impl<A, B> Storable for (A, B)
7where
8    A: Storable,
9    B: Storable,
10{
11    fn to_bytes(&self) -> Cow<[u8]> {
12        match Self::BOUND {
13            Bound::Bounded { max_size, .. } => {
14                let a_bytes = self.0.to_bytes();
15                let b_bytes = self.1.to_bytes();
16                let a_bounds = bounds::<A>();
17                let b_bounds = bounds::<B>();
18                let a_max_size = a_bounds.max_size as usize;
19                let b_max_size = b_bounds.max_size as usize;
20                let a_size_len = bytes_to_store_size_bounded(&a_bounds) as usize;
21                let b_size_len = bytes_to_store_size_bounded(&b_bounds) as usize;
22                let sizes_offset = a_max_size + b_max_size;
23
24                debug_assert!(a_bytes.len() <= a_max_size);
25                debug_assert!(b_bytes.len() <= b_max_size);
26
27                let mut bytes = vec![0; max_size as usize];
28                bytes[..a_bytes.len()].copy_from_slice(a_bytes.as_ref());
29                bytes[a_max_size..a_max_size + b_bytes.len()].copy_from_slice(b_bytes.as_ref());
30
31                encode_size_of_bound(
32                    &mut bytes[sizes_offset..sizes_offset + a_size_len],
33                    a_bytes.len(),
34                    &a_bounds,
35                );
36                encode_size_of_bound(
37                    &mut bytes[sizes_offset + a_size_len..sizes_offset + a_size_len + b_size_len],
38                    b_bytes.len(),
39                    &b_bounds,
40                );
41
42                Cow::Owned(bytes)
43            }
44            _ => todo!("Serializing tuples with unbounded types is not yet supported."),
45        }
46    }
47
48    #[inline]
49    fn from_bytes(bytes: Cow<[u8]>) -> Self {
50        match Self::BOUND {
51            Bound::Bounded { max_size, .. } => {
52                assert_eq!(bytes.len(), max_size as usize);
53                let a_bounds = bounds::<A>();
54                let b_bounds = bounds::<B>();
55                let a_max_size = a_bounds.max_size as usize;
56                let b_max_size = b_bounds.max_size as usize;
57                let sizes_offset = a_max_size + b_max_size;
58                let a_size_len = bytes_to_store_size_bounded(&a_bounds) as usize;
59                let b_size_len = bytes_to_store_size_bounded(&b_bounds) as usize;
60
61                let a_len = decode_size_of_bound(
62                    &bytes[sizes_offset..sizes_offset + a_size_len],
63                    &a_bounds,
64                );
65                let b_len = decode_size_of_bound(
66                    &bytes[sizes_offset + a_size_len..sizes_offset + a_size_len + b_size_len],
67                    &b_bounds,
68                );
69
70                let a = A::from_bytes(Cow::Borrowed(&bytes[..a_len]));
71                let b = B::from_bytes(Cow::Borrowed(&bytes[a_max_size..a_max_size + b_len]));
72                (a, b)
73            }
74            _ => todo!("Deserializing tuples with unbounded types is not yet supported."),
75        }
76    }
77
78    const BOUND: Bound = match (A::BOUND, B::BOUND) {
79        (Bound::Bounded { .. }, Bound::Bounded { .. }) => {
80            let a_bounds = bounds::<A>();
81            let b_bounds = bounds::<B>();
82            Bound::Bounded {
83                max_size: a_bounds.max_size
84                    + b_bounds.max_size
85                    + bytes_to_store_size_bounded(&a_bounds)
86                    + bytes_to_store_size_bounded(&b_bounds),
87                is_fixed_size: a_bounds.is_fixed_size && b_bounds.is_fixed_size,
88            }
89        }
90        _ => Bound::Unbounded,
91    };
92}
93
94fn decode_size_of_bound(src: &[u8], bounds: &Bounds) -> usize {
95    if bounds.is_fixed_size {
96        bounds.max_size as usize
97    } else {
98        decode_size(src, bytes_to_store_size(bounds.max_size as usize))
99    }
100}
101
102fn encode_size_of_bound(dst: &mut [u8], n: usize, bounds: &Bounds) {
103    if !bounds.is_fixed_size {
104        encode_size(dst, n, bytes_to_store_size(bounds.max_size as usize));
105    }
106}
107
108/// Decodes size from the beginning of `src` of length `size_len` and returns it.
109fn decode_size(src: &[u8], size_len: usize) -> usize {
110    match size_len {
111        1 => src[0] as usize,
112        2 => u16::from_be_bytes([src[0], src[1]]) as usize,
113        _ => u32::from_be_bytes([src[0], src[1], src[2], src[3]]) as usize,
114    }
115}
116
117/// Encodes `size` at the beginning of `dst` of length `bytes_to_store_size` bytes.
118fn encode_size(dst: &mut [u8], size_len: usize, bytes: usize) {
119    match bytes {
120        1 => dst[0] = size_len as u8,
121        2 => dst[..2].copy_from_slice(&(size_len as u16).to_be_bytes()),
122        _ => dst[..4].copy_from_slice(&(size_len as u32).to_be_bytes()),
123    }
124}
125
126fn encode_size_lengths(sizes: &[usize]) -> u8 {
127    assert!(sizes.len() <= 4);
128
129    let mut size_lengths_byte: u8 = 0;
130
131    for size in sizes.iter() {
132        let size_length = bytes_to_store_size(*size);
133        // Number of bytes required to store the size of every
134        // element is represented with 2 bits.
135        size_lengths_byte <<= 2;
136        // `size_length` can take value in {1, 2, 4}, but to
137        // compress it into 2 bit we will decrement its value.
138        size_lengths_byte += (size_length - 1) as u8;
139    }
140
141    size_lengths_byte
142}
143
144fn decode_size_lengths(mut encoded_bytes_to_store: u8, number_of_encoded_lengths: u8) -> Vec<u8> {
145    assert!(number_of_encoded_lengths <= 4);
146
147    let mut bytes_to_store_sizes = vec![];
148
149    for _ in 0..number_of_encoded_lengths {
150        // The number of bytes required to store the size of every
151        // element is represented with 2 bits. Hence we use
152        // mask `11`, equivalent to 3 in the decimal system.
153        let mask: u8 = 3;
154        // The number of bytes required to store size can take value
155        // in {1, 2, 4}, but to compress it to 2-bit,
156        // when encoding we decreased the value, hence now we need
157        // to do inverse.
158        let bytes_to_store: u8 = (encoded_bytes_to_store & mask) + 1;
159        bytes_to_store_sizes.push(bytes_to_store);
160        encoded_bytes_to_store >>= 2;
161    }
162
163    // Because encoding and decoding are started on the same
164    // end of the byte, we need to reverse `bytes_to_store_sizes`
165    // to get sizes in order.
166    bytes_to_store_sizes.reverse();
167
168    bytes_to_store_sizes
169}
170
171// Encodes a serialized element `T` in a tuple.
172// The element is assumed to be at the beginning of `dst`.
173// Returns the number of bytes written to `dst`.
174fn encode_tuple_element<T: Storable>(dst: &mut [u8], bytes: &[u8], last: bool) -> usize {
175    let mut offset = 0;
176    if !last && !T::BOUND.is_fixed_size() {
177        let size_len = bytes_to_store_size(bytes.len());
178        encode_size(&mut dst[offset..], bytes.len(), size_len);
179        offset += size_len;
180    }
181    dst[offset..offset + bytes.len()].copy_from_slice(bytes);
182    offset + bytes.len()
183}
184
185// Decodes an element `T` from a tuple.
186//
187// The element is assumed to be at the beginning of `src`.
188// The length of the size of the element should be provided if the element is *not* fixed in size.
189//
190// Returns the element `T` and the number of bytes read from `src`.
191fn decode_tuple_element<T: Storable>(src: &[u8], size_len: Option<u8>, last: bool) -> (T, usize) {
192    let mut read = 0;
193    let size = if let Some(len) = size_len {
194        let s = decode_size(&src[read..], len as usize);
195        read += len as usize;
196        s
197    } else if let Bound::Bounded {
198        max_size,
199        is_fixed_size: true,
200    } = T::BOUND
201    {
202        max_size as usize
203    } else {
204        // This case should only happen for the last element.
205        assert!(last);
206        src.len()
207    };
208    (
209        T::from_bytes(Cow::Borrowed(&src[read..read + size])),
210        read + size,
211    )
212}
213
214// Returns number of bytes required to store encoding of sizes for elements of type A and B.
215const fn sizes_overhead<A: Storable, B: Storable>(a_size: usize, b_size: usize) -> usize {
216    let mut sizes_overhead = 0;
217
218    if !(A::BOUND.is_fixed_size() && B::BOUND.is_fixed_size()) {
219        // 1B for size lengths encoding
220        sizes_overhead += 1;
221
222        if !A::BOUND.is_fixed_size() {
223            sizes_overhead += bytes_to_store_size(a_size);
224        }
225
226        if !B::BOUND.is_fixed_size() {
227            sizes_overhead += bytes_to_store_size(b_size);
228        }
229    }
230
231    sizes_overhead
232}
233
234impl<A, B, C> Storable for (A, B, C)
235where
236    A: Storable,
237    B: Storable,
238    C: Storable,
239{
240    // Tuple (A, B, C) serialization:
241    //   If A and B have fixed size:
242    //     <a_bytes> <b_bytes> <c_bytes>
243    //   Otherwise:
244    //     <size_lengths (1B)> <size_a (0-4B)> <a_bytes> <size_b(0-4B)> <b_bytes> <c_bytes>
245    fn to_bytes(&self) -> Cow<[u8]> {
246        let a_bytes = self.0.to_bytes();
247        let b_bytes = self.1.to_bytes();
248        let c_bytes = self.2.to_bytes();
249        let a_size = a_bytes.len();
250        let b_size = b_bytes.len();
251        let c_size = c_bytes.len();
252
253        let sizes_overhead = sizes_overhead::<A, B>(a_size, b_size);
254        let output_size = a_size + b_size + c_size + sizes_overhead;
255        let mut bytes = vec![0; output_size];
256        let mut offset = 0;
257
258        if sizes_overhead != 0 {
259            bytes[offset] = encode_size_lengths(&[a_size, b_size]);
260            offset += 1;
261        }
262
263        offset += encode_tuple_element::<A>(&mut bytes[offset..], a_bytes.as_ref(), false);
264        offset += encode_tuple_element::<B>(&mut bytes[offset..], b_bytes.as_ref(), false);
265        offset += encode_tuple_element::<C>(&mut bytes[offset..], c_bytes.as_ref(), true);
266
267        debug_assert_eq!(offset, output_size);
268        Cow::Owned(bytes)
269    }
270
271    #[inline]
272    fn from_bytes(bytes: Cow<[u8]>) -> Self {
273        let mut offset = 0;
274        let mut size_lengths = [None, None];
275
276        if !(A::BOUND.is_fixed_size() && B::BOUND.is_fixed_size()) {
277            let lengths = decode_size_lengths(bytes[0], 2);
278            offset += 1;
279            if !A::BOUND.is_fixed_size() {
280                size_lengths[0] = Some(lengths[0]);
281            }
282            if !B::BOUND.is_fixed_size() {
283                size_lengths[1] = Some(lengths[1]);
284            }
285        }
286
287        let (a, read) = decode_tuple_element::<A>(&bytes[offset..], size_lengths[0], false);
288        offset += read;
289        let (b, read) = decode_tuple_element::<B>(&bytes[offset..], size_lengths[1], false);
290        offset += read;
291        let (c, read) = decode_tuple_element::<C>(&bytes[offset..], None, true);
292        offset += read;
293
294        debug_assert_eq!(offset, bytes.len());
295        (a, b, c)
296    }
297
298    const BOUND: Bound = match (A::BOUND, B::BOUND, C::BOUND) {
299        (Bound::Bounded { .. }, Bound::Bounded { .. }, Bound::Bounded { .. }) => {
300            let a_bounds = bounds::<A>();
301            let b_bounds = bounds::<B>();
302            let c_bounds = bounds::<C>();
303            let sizes_overhead =
304                sizes_overhead::<A, B>(a_bounds.max_size as usize, b_bounds.max_size as usize)
305                    as u32;
306            Bound::Bounded {
307                max_size: a_bounds.max_size
308                    + b_bounds.max_size
309                    + c_bounds.max_size
310                    + sizes_overhead,
311                is_fixed_size: a_bounds.is_fixed_size
312                    && b_bounds.is_fixed_size
313                    && c_bounds.is_fixed_size,
314            }
315        }
316        _ => Bound::Unbounded,
317    };
318}