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