postcard/
max_size.rs

1#[cfg(feature = "alloc")]
2extern crate alloc;
3
4#[cfg(feature = "alloc")]
5use alloc::{boxed::Box, rc::Rc};
6
7#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
8use alloc::sync::Arc;
9
10use crate::varint::varint_max;
11use core::{
12    marker::PhantomData,
13    num::{
14        NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
15        NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
16    },
17};
18
19/// This trait is used to enforce the maximum size required to
20/// store the serialization of a given type.
21pub trait MaxSize {
22    /// The maximum possible size that the serialization of this
23    /// type can have, in bytes.
24    const POSTCARD_MAX_SIZE: usize;
25}
26
27impl MaxSize for bool {
28    const POSTCARD_MAX_SIZE: usize = 1;
29}
30
31impl MaxSize for i8 {
32    const POSTCARD_MAX_SIZE: usize = 1;
33}
34
35impl MaxSize for i16 {
36    const POSTCARD_MAX_SIZE: usize = varint_max::<Self>();
37}
38
39impl MaxSize for i32 {
40    const POSTCARD_MAX_SIZE: usize = varint_max::<Self>();
41}
42
43impl MaxSize for i64 {
44    const POSTCARD_MAX_SIZE: usize = varint_max::<Self>();
45}
46
47impl MaxSize for i128 {
48    const POSTCARD_MAX_SIZE: usize = varint_max::<Self>();
49}
50
51impl MaxSize for isize {
52    const POSTCARD_MAX_SIZE: usize = varint_max::<Self>();
53}
54
55impl MaxSize for u8 {
56    const POSTCARD_MAX_SIZE: usize = 1;
57}
58
59impl MaxSize for u16 {
60    const POSTCARD_MAX_SIZE: usize = varint_max::<Self>();
61}
62
63impl MaxSize for u32 {
64    const POSTCARD_MAX_SIZE: usize = varint_max::<Self>();
65}
66
67impl MaxSize for u64 {
68    const POSTCARD_MAX_SIZE: usize = varint_max::<Self>();
69}
70
71impl MaxSize for u128 {
72    const POSTCARD_MAX_SIZE: usize = varint_max::<Self>();
73}
74
75impl MaxSize for usize {
76    const POSTCARD_MAX_SIZE: usize = varint_max::<Self>();
77}
78
79impl MaxSize for f32 {
80    const POSTCARD_MAX_SIZE: usize = 4;
81}
82
83impl MaxSize for f64 {
84    const POSTCARD_MAX_SIZE: usize = 8;
85}
86
87impl MaxSize for char {
88    const POSTCARD_MAX_SIZE: usize = 5;
89}
90
91impl<T: MaxSize> MaxSize for Option<T> {
92    const POSTCARD_MAX_SIZE: usize = T::POSTCARD_MAX_SIZE + 1;
93}
94
95impl<T: MaxSize, E: MaxSize> MaxSize for Result<T, E> {
96    const POSTCARD_MAX_SIZE: usize = max(T::POSTCARD_MAX_SIZE, E::POSTCARD_MAX_SIZE) + 1;
97}
98
99impl MaxSize for () {
100    const POSTCARD_MAX_SIZE: usize = 0;
101}
102
103impl<T: MaxSize, const N: usize> MaxSize for [T; N] {
104    const POSTCARD_MAX_SIZE: usize = T::POSTCARD_MAX_SIZE * N;
105}
106
107impl<T: MaxSize> MaxSize for &'_ T {
108    const POSTCARD_MAX_SIZE: usize = T::POSTCARD_MAX_SIZE;
109}
110
111impl<T: MaxSize> MaxSize for &'_ mut T {
112    const POSTCARD_MAX_SIZE: usize = T::POSTCARD_MAX_SIZE;
113}
114
115impl MaxSize for NonZeroI8 {
116    const POSTCARD_MAX_SIZE: usize = i8::POSTCARD_MAX_SIZE;
117}
118
119impl MaxSize for NonZeroI16 {
120    const POSTCARD_MAX_SIZE: usize = i16::POSTCARD_MAX_SIZE;
121}
122
123impl MaxSize for NonZeroI32 {
124    const POSTCARD_MAX_SIZE: usize = i32::POSTCARD_MAX_SIZE;
125}
126
127impl MaxSize for NonZeroI64 {
128    const POSTCARD_MAX_SIZE: usize = i64::POSTCARD_MAX_SIZE;
129}
130
131impl MaxSize for NonZeroI128 {
132    const POSTCARD_MAX_SIZE: usize = i128::POSTCARD_MAX_SIZE;
133}
134
135impl MaxSize for NonZeroIsize {
136    const POSTCARD_MAX_SIZE: usize = isize::POSTCARD_MAX_SIZE;
137}
138
139impl MaxSize for NonZeroU8 {
140    const POSTCARD_MAX_SIZE: usize = u8::POSTCARD_MAX_SIZE;
141}
142
143impl MaxSize for NonZeroU16 {
144    const POSTCARD_MAX_SIZE: usize = u16::POSTCARD_MAX_SIZE;
145}
146
147impl MaxSize for NonZeroU32 {
148    const POSTCARD_MAX_SIZE: usize = u32::POSTCARD_MAX_SIZE;
149}
150
151impl MaxSize for NonZeroU64 {
152    const POSTCARD_MAX_SIZE: usize = u64::POSTCARD_MAX_SIZE;
153}
154
155impl MaxSize for NonZeroU128 {
156    const POSTCARD_MAX_SIZE: usize = u128::POSTCARD_MAX_SIZE;
157}
158
159impl MaxSize for NonZeroUsize {
160    const POSTCARD_MAX_SIZE: usize = usize::POSTCARD_MAX_SIZE;
161}
162
163impl<T> MaxSize for PhantomData<T> {
164    const POSTCARD_MAX_SIZE: usize = 0;
165}
166
167impl<A: MaxSize> MaxSize for (A,) {
168    const POSTCARD_MAX_SIZE: usize = A::POSTCARD_MAX_SIZE;
169}
170
171impl<A: MaxSize, B: MaxSize> MaxSize for (A, B) {
172    const POSTCARD_MAX_SIZE: usize = A::POSTCARD_MAX_SIZE + B::POSTCARD_MAX_SIZE;
173}
174
175impl<A: MaxSize, B: MaxSize, C: MaxSize> MaxSize for (A, B, C) {
176    const POSTCARD_MAX_SIZE: usize =
177        A::POSTCARD_MAX_SIZE + B::POSTCARD_MAX_SIZE + C::POSTCARD_MAX_SIZE;
178}
179
180impl<A: MaxSize, B: MaxSize, C: MaxSize, D: MaxSize> MaxSize for (A, B, C, D) {
181    const POSTCARD_MAX_SIZE: usize =
182        A::POSTCARD_MAX_SIZE + B::POSTCARD_MAX_SIZE + C::POSTCARD_MAX_SIZE + D::POSTCARD_MAX_SIZE;
183}
184
185impl<A: MaxSize, B: MaxSize, C: MaxSize, D: MaxSize, E: MaxSize> MaxSize for (A, B, C, D, E) {
186    const POSTCARD_MAX_SIZE: usize = A::POSTCARD_MAX_SIZE
187        + B::POSTCARD_MAX_SIZE
188        + C::POSTCARD_MAX_SIZE
189        + D::POSTCARD_MAX_SIZE
190        + E::POSTCARD_MAX_SIZE;
191}
192
193impl<A: MaxSize, B: MaxSize, C: MaxSize, D: MaxSize, E: MaxSize, F: MaxSize> MaxSize
194    for (A, B, C, D, E, F)
195{
196    const POSTCARD_MAX_SIZE: usize = A::POSTCARD_MAX_SIZE
197        + B::POSTCARD_MAX_SIZE
198        + C::POSTCARD_MAX_SIZE
199        + D::POSTCARD_MAX_SIZE
200        + E::POSTCARD_MAX_SIZE
201        + F::POSTCARD_MAX_SIZE;
202}
203
204#[cfg(feature = "alloc")]
205#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
206impl<T: MaxSize> MaxSize for Box<T> {
207    const POSTCARD_MAX_SIZE: usize = T::POSTCARD_MAX_SIZE;
208}
209
210#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
211#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", target_has_atomic = "ptr"))))]
212impl<T: MaxSize> MaxSize for Arc<T> {
213    const POSTCARD_MAX_SIZE: usize = T::POSTCARD_MAX_SIZE;
214}
215
216#[cfg(feature = "alloc")]
217#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
218impl<T: MaxSize> MaxSize for Rc<T> {
219    const POSTCARD_MAX_SIZE: usize = T::POSTCARD_MAX_SIZE;
220}
221
222#[cfg(feature = "heapless")]
223#[cfg_attr(docsrs, doc(cfg(feature = "heapless")))]
224impl<T: MaxSize, const N: usize> MaxSize for heapless::Vec<T, N> {
225    const POSTCARD_MAX_SIZE: usize = <[T; N]>::POSTCARD_MAX_SIZE + varint_size(N);
226}
227
228#[cfg(feature = "heapless")]
229#[cfg_attr(docsrs, doc(cfg(feature = "heapless")))]
230impl<const N: usize> MaxSize for heapless::String<N> {
231    const POSTCARD_MAX_SIZE: usize = <[u8; N]>::POSTCARD_MAX_SIZE + varint_size(N);
232}
233
234#[cfg(feature = "heapless")]
235const fn varint_size(max_n: usize) -> usize {
236    const BITS_PER_BYTE: usize = 8;
237    const BITS_PER_VARINT_BYTE: usize = 7;
238
239    if max_n == 0 {
240        return 1;
241    }
242
243    // How many data bits do we need for `max_n`.
244    let bits = core::mem::size_of::<usize>() * BITS_PER_BYTE - max_n.leading_zeros() as usize;
245
246    // We add (BITS_PER_BYTE - 1), to ensure any integer divisions
247    // with a remainder will always add exactly one full byte, but
248    // an evenly divided number of bits will be the same
249    let roundup_bits = bits + (BITS_PER_VARINT_BYTE - 1);
250
251    // Apply division, using normal "round down" integer division
252    roundup_bits / BITS_PER_VARINT_BYTE
253}
254
255const fn max(lhs: usize, rhs: usize) -> usize {
256    if lhs > rhs {
257        lhs
258    } else {
259        rhs
260    }
261}
262
263#[cfg(any(feature = "alloc", feature = "use-std"))]
264#[cfg(test)]
265mod tests {
266    extern crate alloc;
267
268    use super::*;
269    use alloc::rc::Rc;
270
271    #[cfg(target_has_atomic = "ptr")]
272    use alloc::sync::Arc;
273
274    #[test]
275    fn box_max_size() {
276        assert_eq!(Box::<u8>::POSTCARD_MAX_SIZE, 1);
277        assert_eq!(Box::<u32>::POSTCARD_MAX_SIZE, 5);
278        assert_eq!(Box::<(u128, [u8; 8])>::POSTCARD_MAX_SIZE, 27);
279    }
280
281    #[test]
282    #[cfg(target_has_atomic = "ptr")]
283    fn arc_max_size() {
284        assert_eq!(Arc::<u8>::POSTCARD_MAX_SIZE, 1);
285        assert_eq!(Arc::<u32>::POSTCARD_MAX_SIZE, 5);
286        assert_eq!(Arc::<(u128, [u8; 8])>::POSTCARD_MAX_SIZE, 27);
287    }
288
289    #[test]
290    fn rc_max_size() {
291        assert_eq!(Rc::<u8>::POSTCARD_MAX_SIZE, 1);
292        assert_eq!(Rc::<u32>::POSTCARD_MAX_SIZE, 5);
293        assert_eq!(Rc::<(u128, [u8; 8])>::POSTCARD_MAX_SIZE, 27);
294    }
295}