ic_stable_memory/encoding/
fixed_size.rs1use candid::{Int, Nat, Principal};
15use num_bigint::{BigInt, BigUint, Sign};
16
17pub trait AsFixedSizeBytes {
27 const SIZE: usize;
29
30 type Buf: Buffer;
32
33 fn as_fixed_size_bytes(&self, buf: &mut [u8]);
38
39 fn from_fixed_size_bytes(buf: &[u8]) -> Self;
44
45 fn as_new_fixed_size_bytes(&self) -> Self::Buf {
47 let mut buf = Self::Buf::new(Self::SIZE);
48 self.as_fixed_size_bytes(buf._deref_mut());
49
50 buf
51 }
52}
53
54macro_rules! impl_for_number {
55 ($ty:ty) => {
56 impl AsFixedSizeBytes for $ty {
57 const SIZE: usize = std::mem::size_of::<$ty>();
58 type Buf = [u8; Self::SIZE];
59
60 #[inline]
61 fn as_fixed_size_bytes(&self, buf: &mut [u8]) {
62 buf.copy_from_slice(&self.to_le_bytes())
63 }
64
65 #[inline]
66 fn from_fixed_size_bytes(buf: &[u8]) -> Self {
67 let mut b = Self::Buf::new(Self::SIZE);
68 b.copy_from_slice(buf);
69
70 Self::from_le_bytes(b)
71 }
72 }
73 };
74}
75
76impl_for_number!(i8);
77impl_for_number!(u8);
78impl_for_number!(i16);
79impl_for_number!(u16);
80impl_for_number!(i32);
81impl_for_number!(u32);
82impl_for_number!(i64);
83impl_for_number!(u64);
84impl_for_number!(i128);
85impl_for_number!(u128);
86impl_for_number!(isize);
87impl_for_number!(usize);
88impl_for_number!(f32);
89impl_for_number!(f64);
90
91impl AsFixedSizeBytes for char {
92 const SIZE: usize = u32::SIZE;
93 type Buf = [u8; Self::SIZE];
94
95 fn as_fixed_size_bytes(&self, buf: &mut [u8]) {
96 u32::from(*self).as_fixed_size_bytes(buf)
97 }
98
99 fn from_fixed_size_bytes(buf: &[u8]) -> Self {
100 char::try_from(u32::from_fixed_size_bytes(buf)).unwrap()
101 }
102}
103
104impl AsFixedSizeBytes for () {
105 const SIZE: usize = 0;
106 type Buf = [u8; 0];
107
108 #[inline]
109 fn as_fixed_size_bytes(&self, _: &mut [u8]) {}
110
111 #[inline]
112 fn from_fixed_size_bytes(_: &[u8]) -> Self {}
113}
114
115impl AsFixedSizeBytes for bool {
116 const SIZE: usize = 1;
117 type Buf = [u8; 1];
118
119 #[inline]
120 fn as_fixed_size_bytes(&self, buf: &mut [u8]) {
121 if *self {
122 buf[0] = 1;
123 } else {
124 buf[0] = 0;
125 }
126 }
127
128 #[inline]
129 fn from_fixed_size_bytes(buf: &[u8]) -> Self {
130 assert!(buf[0] < 2);
131
132 buf[0] == 1
133 }
134}
135
136impl<T: AsFixedSizeBytes> AsFixedSizeBytes for Option<T> {
137 const SIZE: usize = T::SIZE + 1;
138 type Buf = Vec<u8>;
139
140 #[inline]
141 fn as_fixed_size_bytes(&self, buf: &mut [u8]) {
142 if let Some(it) = self {
143 buf[0] = 1;
144 it.as_fixed_size_bytes(&mut buf[1..Self::SIZE]);
145 } else {
146 buf[0] = 0;
147 }
148 }
149
150 #[inline]
151 fn from_fixed_size_bytes(buf: &[u8]) -> Self {
152 if buf[0] == 1 {
153 Some(T::from_fixed_size_bytes(&buf[1..Self::SIZE]))
154 } else {
155 None
156 }
157 }
158}
159
160impl<const N: usize> AsFixedSizeBytes for [(); N] {
161 const SIZE: usize = 0;
162 type Buf = [u8; 0];
163
164 #[inline]
165 fn as_fixed_size_bytes(&self, _: &mut [u8]) {}
166
167 #[inline]
168 fn from_fixed_size_bytes(_: &[u8]) -> Self {
169 [(); N]
170 }
171}
172
173macro_rules! impl_for_single_byte_type_arr {
174 ($ty:ty, $zero:expr) => {
175 impl<const N: usize> AsFixedSizeBytes for [$ty; N] {
176 const SIZE: usize = N;
177 type Buf = [u8; N];
178
179 fn as_fixed_size_bytes(&self, buf: &mut [u8]) {
180 for i in 0..N {
181 let from = i * <$ty>::SIZE;
182 let to = from + <$ty>::SIZE;
183
184 self[i].as_fixed_size_bytes(&mut buf[from..to]);
185 }
186 }
187
188 fn from_fixed_size_bytes(buf: &[u8]) -> Self {
189 let mut it = [$zero; N];
190
191 for i in 0..N {
192 let from = i * <$ty>::SIZE;
193 let to = from + <$ty>::SIZE;
194
195 it[i] = <$ty>::from_fixed_size_bytes(&buf[from..to]);
196 }
197
198 it
199 }
200 }
201 };
202}
203
204impl_for_single_byte_type_arr!(bool, false);
205impl_for_single_byte_type_arr!(i8, 0);
206impl_for_single_byte_type_arr!(u8, 0);
207
208macro_rules! impl_for_number_arr {
209 ($ty:ty, $zero:expr) => {
210 impl<const N: usize> AsFixedSizeBytes for [$ty; N] {
211 const SIZE: usize = N;
212 type Buf = Vec<u8>;
213
214 fn as_fixed_size_bytes(&self, buf: &mut [u8]) {
215 for i in 0..N {
216 let from = i * <$ty>::SIZE;
217 let to = from + <$ty>::SIZE;
218
219 self[i].as_fixed_size_bytes(&mut buf[from..to]);
220 }
221 }
222
223 fn from_fixed_size_bytes(buf: &[u8]) -> Self {
224 let mut it = [$zero; N];
225
226 for i in 0..N {
227 let from = i * <$ty>::SIZE;
228 let to = from + <$ty>::SIZE;
229
230 it[i] = <$ty>::from_fixed_size_bytes(&buf[from..to]);
231 }
232
233 it
234 }
235 }
236 };
237}
238
239impl_for_number_arr!(i16, 0);
240impl_for_number_arr!(u16, 0);
241impl_for_number_arr!(i32, 0);
242impl_for_number_arr!(u32, 0);
243impl_for_number_arr!(i64, 0);
244impl_for_number_arr!(u64, 0);
245impl_for_number_arr!(i128, 0);
246impl_for_number_arr!(u128, 0);
247impl_for_number_arr!(isize, 0);
248impl_for_number_arr!(usize, 0);
249impl_for_number_arr!(f32, 0.0);
250impl_for_number_arr!(f64, 0.0);
251
252impl<const N: usize> AsFixedSizeBytes for [char; N] {
253 const SIZE: usize = N * char::SIZE;
254 type Buf = Vec<u8>;
255
256 fn as_fixed_size_bytes(&self, buf: &mut [u8]) {
257 let mut from = 0;
258
259 for c in self {
260 c.as_fixed_size_bytes(&mut buf[from..(from + u32::SIZE)]);
261 from += u32::SIZE;
262 }
263 }
264
265 fn from_fixed_size_bytes(buf: &[u8]) -> Self {
266 let mut s = [char::default(); N];
267
268 for from in 0..N {
269 s[from] =
270 char::from_fixed_size_bytes(&buf[(from * u32::SIZE)..((from + 1) * u32::SIZE)]);
271 }
272
273 s
274 }
275}
276
277impl<A: AsFixedSizeBytes> AsFixedSizeBytes for (A,) {
278 const SIZE: usize = A::SIZE;
279 type Buf = Vec<u8>;
280
281 fn as_fixed_size_bytes(&self, buf: &mut [u8]) {
282 self.0.as_fixed_size_bytes(buf)
283 }
284
285 fn from_fixed_size_bytes(buf: &[u8]) -> Self {
286 (A::from_fixed_size_bytes(buf),)
287 }
288}
289impl<A: AsFixedSizeBytes, B: AsFixedSizeBytes> AsFixedSizeBytes for (A, B) {
290 const SIZE: usize = A::SIZE + B::SIZE;
291 type Buf = Vec<u8>;
292
293 fn as_fixed_size_bytes(&self, buf: &mut [u8]) {
294 self.0.as_fixed_size_bytes(&mut buf[0..A::SIZE]);
295 self.1
296 .as_fixed_size_bytes(&mut buf[A::SIZE..(A::SIZE + B::SIZE)]);
297 }
298
299 fn from_fixed_size_bytes(buf: &[u8]) -> Self {
300 (
301 A::from_fixed_size_bytes(&buf[0..A::SIZE]),
302 B::from_fixed_size_bytes(&buf[A::SIZE..(A::SIZE + B::SIZE)]),
303 )
304 }
305}
306impl<A: AsFixedSizeBytes, B: AsFixedSizeBytes, C: AsFixedSizeBytes> AsFixedSizeBytes for (A, B, C) {
307 const SIZE: usize = A::SIZE + B::SIZE + C::SIZE;
308 type Buf = Vec<u8>;
309
310 fn as_fixed_size_bytes(&self, buf: &mut [u8]) {
311 self.0.as_fixed_size_bytes(&mut buf[0..A::SIZE]);
312 self.1
313 .as_fixed_size_bytes(&mut buf[A::SIZE..(A::SIZE + B::SIZE)]);
314 self.2
315 .as_fixed_size_bytes(&mut buf[(A::SIZE + B::SIZE)..(A::SIZE + B::SIZE + C::SIZE)]);
316 }
317
318 fn from_fixed_size_bytes(buf: &[u8]) -> Self {
319 (
320 A::from_fixed_size_bytes(&buf[0..A::SIZE]),
321 B::from_fixed_size_bytes(&buf[A::SIZE..(A::SIZE + B::SIZE)]),
322 C::from_fixed_size_bytes(&buf[(A::SIZE + B::SIZE)..(A::SIZE + B::SIZE + C::SIZE)]),
323 )
324 }
325}
326impl<A: AsFixedSizeBytes, B: AsFixedSizeBytes, C: AsFixedSizeBytes, D: AsFixedSizeBytes>
327 AsFixedSizeBytes for (A, B, C, D)
328{
329 const SIZE: usize = A::SIZE + B::SIZE + C::SIZE + D::SIZE;
330 type Buf = Vec<u8>;
331
332 fn as_fixed_size_bytes(&self, buf: &mut [u8]) {
333 self.0.as_fixed_size_bytes(&mut buf[0..A::SIZE]);
334 self.1
335 .as_fixed_size_bytes(&mut buf[A::SIZE..(A::SIZE + B::SIZE)]);
336 self.2
337 .as_fixed_size_bytes(&mut buf[(A::SIZE + B::SIZE)..(A::SIZE + B::SIZE + C::SIZE)]);
338 self.3.as_fixed_size_bytes(
339 &mut buf[(A::SIZE + B::SIZE + C::SIZE)..(A::SIZE + B::SIZE + C::SIZE + D::SIZE)],
340 );
341 }
342
343 fn from_fixed_size_bytes(buf: &[u8]) -> Self {
344 (
345 A::from_fixed_size_bytes(&buf[0..A::SIZE]),
346 B::from_fixed_size_bytes(&buf[A::SIZE..(A::SIZE + B::SIZE)]),
347 C::from_fixed_size_bytes(&buf[(A::SIZE + B::SIZE)..(A::SIZE + B::SIZE + C::SIZE)]),
348 D::from_fixed_size_bytes(
349 &buf[(A::SIZE + B::SIZE + C::SIZE)..(A::SIZE + B::SIZE + C::SIZE + D::SIZE)],
350 ),
351 )
352 }
353}
354impl<
355 A: AsFixedSizeBytes,
356 B: AsFixedSizeBytes,
357 C: AsFixedSizeBytes,
358 D: AsFixedSizeBytes,
359 E: AsFixedSizeBytes,
360 > AsFixedSizeBytes for (A, B, C, D, E)
361{
362 const SIZE: usize = A::SIZE + B::SIZE + C::SIZE + D::SIZE + E::SIZE;
363 type Buf = Vec<u8>;
364
365 fn as_fixed_size_bytes(&self, buf: &mut [u8]) {
366 self.0.as_fixed_size_bytes(&mut buf[0..A::SIZE]);
367 self.1
368 .as_fixed_size_bytes(&mut buf[A::SIZE..(A::SIZE + B::SIZE)]);
369 self.2
370 .as_fixed_size_bytes(&mut buf[(A::SIZE + B::SIZE)..(A::SIZE + B::SIZE + C::SIZE)]);
371 self.3.as_fixed_size_bytes(
372 &mut buf[(A::SIZE + B::SIZE + C::SIZE)..(A::SIZE + B::SIZE + C::SIZE + D::SIZE)],
373 );
374 self.4.as_fixed_size_bytes(
375 &mut buf[(A::SIZE + B::SIZE + C::SIZE + D::SIZE)
376 ..(A::SIZE + B::SIZE + C::SIZE + D::SIZE + E::SIZE)],
377 );
378 }
379
380 fn from_fixed_size_bytes(buf: &[u8]) -> Self {
381 (
382 A::from_fixed_size_bytes(&buf[0..A::SIZE]),
383 B::from_fixed_size_bytes(&buf[A::SIZE..(A::SIZE + B::SIZE)]),
384 C::from_fixed_size_bytes(&buf[(A::SIZE + B::SIZE)..(A::SIZE + B::SIZE + C::SIZE)]),
385 D::from_fixed_size_bytes(
386 &buf[(A::SIZE + B::SIZE + C::SIZE)..(A::SIZE + B::SIZE + C::SIZE + D::SIZE)],
387 ),
388 E::from_fixed_size_bytes(
389 &buf[(A::SIZE + B::SIZE + C::SIZE + D::SIZE)
390 ..(A::SIZE + B::SIZE + C::SIZE + D::SIZE + E::SIZE)],
391 ),
392 )
393 }
394}
395impl<
396 A: AsFixedSizeBytes,
397 B: AsFixedSizeBytes,
398 C: AsFixedSizeBytes,
399 D: AsFixedSizeBytes,
400 E: AsFixedSizeBytes,
401 F: AsFixedSizeBytes,
402 > AsFixedSizeBytes for (A, B, C, D, E, F)
403{
404 const SIZE: usize = A::SIZE + B::SIZE + C::SIZE + D::SIZE + E::SIZE + F::SIZE;
405 type Buf = Vec<u8>;
406
407 fn as_fixed_size_bytes(&self, buf: &mut [u8]) {
408 self.0.as_fixed_size_bytes(&mut buf[0..A::SIZE]);
409 self.1
410 .as_fixed_size_bytes(&mut buf[A::SIZE..(A::SIZE + B::SIZE)]);
411 self.2
412 .as_fixed_size_bytes(&mut buf[(A::SIZE + B::SIZE)..(A::SIZE + B::SIZE + C::SIZE)]);
413 self.3.as_fixed_size_bytes(
414 &mut buf[(A::SIZE + B::SIZE + C::SIZE)..(A::SIZE + B::SIZE + C::SIZE + D::SIZE)],
415 );
416 self.4.as_fixed_size_bytes(
417 &mut buf[(A::SIZE + B::SIZE + C::SIZE + D::SIZE)
418 ..(A::SIZE + B::SIZE + C::SIZE + D::SIZE + E::SIZE)],
419 );
420 self.5.as_fixed_size_bytes(
421 &mut buf[(A::SIZE + B::SIZE + C::SIZE + D::SIZE + E::SIZE)
422 ..(A::SIZE + B::SIZE + C::SIZE + D::SIZE + E::SIZE + F::SIZE)],
423 );
424 }
425
426 fn from_fixed_size_bytes(buf: &[u8]) -> Self {
427 (
428 A::from_fixed_size_bytes(&buf[0..A::SIZE]),
429 B::from_fixed_size_bytes(&buf[A::SIZE..(A::SIZE + B::SIZE)]),
430 C::from_fixed_size_bytes(&buf[(A::SIZE + B::SIZE)..(A::SIZE + B::SIZE + C::SIZE)]),
431 D::from_fixed_size_bytes(
432 &buf[(A::SIZE + B::SIZE + C::SIZE)..(A::SIZE + B::SIZE + C::SIZE + D::SIZE)],
433 ),
434 E::from_fixed_size_bytes(
435 &buf[(A::SIZE + B::SIZE + C::SIZE + D::SIZE)
436 ..(A::SIZE + B::SIZE + C::SIZE + D::SIZE + E::SIZE)],
437 ),
438 F::from_fixed_size_bytes(
439 &buf[(A::SIZE + B::SIZE + C::SIZE + D::SIZE + E::SIZE)
440 ..(A::SIZE + B::SIZE + C::SIZE + D::SIZE + E::SIZE + F::SIZE)],
441 ),
442 )
443 }
444}
445
446impl AsFixedSizeBytes for Principal {
447 const SIZE: usize = 30;
448 type Buf = [u8; Self::SIZE];
449
450 fn as_fixed_size_bytes(&self, buf: &mut [u8]) {
451 let slice = self.as_slice();
452
453 buf[0] = slice.len() as u8;
454 buf[1..(1 + slice.len())].copy_from_slice(slice);
455 }
456
457 fn from_fixed_size_bytes(buf: &[u8]) -> Self {
458 let len = buf[0] as usize;
459
460 Principal::from_slice(&buf[1..(1 + len)])
461 }
462}
463
464impl AsFixedSizeBytes for Nat {
465 const SIZE: usize = 32;
466 type Buf = [u8; Self::SIZE];
467
468 fn as_fixed_size_bytes(&self, buf: &mut [u8]) {
469 let vec = self.0.to_bytes_le();
470 buf[0..vec.len()].copy_from_slice(&vec);
471 }
472
473 fn from_fixed_size_bytes(buf: &[u8]) -> Self {
474 let it = BigUint::from_bytes_le(buf);
475
476 Nat(it)
477 }
478}
479
480impl AsFixedSizeBytes for Int {
481 const SIZE: usize = 32;
482 type Buf = [u8; Self::SIZE];
483
484 fn as_fixed_size_bytes(&self, buf: &mut [u8]) {
485 let (sign, bytes) = self.0.to_bytes_le();
486
487 buf[0] = match sign {
488 Sign::Plus => 0u8,
489 Sign::Minus => 1u8,
490 Sign::NoSign => 2u8,
491 };
492
493 buf[1..(1 + bytes.len())].copy_from_slice(&bytes);
494 }
495
496 fn from_fixed_size_bytes(buf: &[u8]) -> Self {
497 let sign = match buf[0] {
498 0 => Sign::Plus,
499 1 => Sign::Minus,
500 2 => Sign::NoSign,
501 _ => unreachable!(),
502 };
503
504 let it = BigInt::from_bytes_le(sign, &buf[1..]);
505
506 Int(it)
507 }
508}
509
510pub trait Buffer: private::Sealed {
514 #[doc(hidden)]
515 fn new(size: usize) -> Self;
516 #[doc(hidden)]
517 fn _deref(&self) -> &[u8];
518 #[doc(hidden)]
519 fn _deref_mut(&mut self) -> &mut [u8];
520}
521
522impl<const N: usize> Buffer for [u8; N] {
523 #[inline]
524 fn new(_: usize) -> Self {
525 [0u8; N]
526 }
527
528 #[inline]
529 fn _deref(&self) -> &[u8] {
530 unsafe { std::slice::from_raw_parts(self as *const u8, self.len()) }
531 }
532
533 #[inline]
534 fn _deref_mut(&mut self) -> &mut [u8] {
535 unsafe { std::slice::from_raw_parts_mut(self as *mut u8, self.len()) }
536 }
537}
538
539impl Buffer for Vec<u8> {
540 #[inline]
541 fn new(size: usize) -> Self {
542 vec![0u8; size]
543 }
544
545 #[inline]
546 fn _deref(&self) -> &[u8] {
547 unsafe { std::slice::from_raw_parts(self.as_ptr(), self.len()) }
548 }
549
550 #[inline]
551 fn _deref_mut(&mut self) -> &mut [u8] {
552 unsafe { std::slice::from_raw_parts_mut(self.as_mut_ptr(), self.len()) }
553 }
554}
555
556mod private {
557 pub trait Sealed {}
558
559 impl<const N: usize> Sealed for [u8; N] {}
560 impl Sealed for Vec<u8> {}
561}