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