ic_stable_structures/storable/
tuples.rs1use 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
108fn 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
117fn 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 size_lengths_byte <<= 2;
136 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 let mask: u8 = 3;
154 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 bytes_to_store_sizes.reverse();
167
168 bytes_to_store_sizes
169}
170
171fn 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
185fn 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 assert!(last);
206 src.len()
207 };
208 (
209 T::from_bytes(Cow::Borrowed(&src[read..read + size])),
210 read + size,
211 )
212}
213
214const 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 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 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}