1use super::const_writer::{
20 max_size_add, max_size_array, max_size_bool, max_size_f32, max_size_f64, max_size_i16,
21 max_size_i32, max_size_i64, max_size_max, max_size_opaque_fixed, max_size_opaque_variable,
22 max_size_u16, max_size_u32, max_size_u64, size_i32,
23};
24#[cfg(feature = "int128")]
25use super::const_writer::{max_size_i128, max_size_u128};
26use core::convert::Infallible;
27use core::marker::PhantomData;
28use xdr_common::{BytesM, StaticIfNoAlloc, StringM, VecM};
29
30pub trait ConstMaxSize {
39 const MAX_SIZE: Option<usize>;
41}
42
43macro_rules! impl_primitive {
44 ($($ty:ty => $max_fn:ident),* $(,)?) => {$(
45 impl ConstMaxSize for $ty {
46 const MAX_SIZE: Option<usize> = Some($max_fn());
47 }
48 )*};
49}
50
51impl_primitive! {
52 i16 => max_size_i16,
53 u16 => max_size_u16,
54 i32 => max_size_i32,
55 u32 => max_size_u32,
56 i64 => max_size_i64,
57 u64 => max_size_u64,
58 bool => max_size_bool,
59 f32 => max_size_f32,
60 f64 => max_size_f64,
61}
62
63#[cfg(feature = "int128")]
64impl_primitive! {
65 i128 => max_size_i128,
66 u128 => max_size_u128,
67}
68
69impl<const N: usize> ConstMaxSize for [u8; N] {
70 const MAX_SIZE: Option<usize> = max_size_opaque_fixed(N);
71}
72
73impl<T: ConstMaxSize, const N: usize> ConstMaxSize for [T; N] {
74 const MAX_SIZE: Option<usize> = max_size_array(N, T::MAX_SIZE);
75}
76
77impl<T: ?Sized> ConstMaxSize for &T {
80 const MAX_SIZE: Option<usize> = None;
81}
82
83#[cfg(feature = "alloc")]
89impl<T: ?Sized> ConstMaxSize for alloc::boxed::Box<T> {
90 const MAX_SIZE: Option<usize> = None;
91}
92
93#[cfg(not(feature = "alloc"))]
96impl<T: ConstMaxSize> ConstMaxSize for xdr_common::Box<T> {
97 const MAX_SIZE: Option<usize> = T::MAX_SIZE;
98}
99
100impl<T: ConstMaxSize> ConstMaxSize for Option<T> {
101 const MAX_SIZE: Option<usize> = max_size_add(Some(size_i32(1)), T::MAX_SIZE);
102}
103
104impl<T: ConstMaxSize, E: ConstMaxSize> ConstMaxSize for Result<T, E> {
105 const MAX_SIZE: Option<usize> =
106 max_size_add(Some(size_i32(1)), max_size_max(T::MAX_SIZE, E::MAX_SIZE));
107}
108
109impl<T> ConstMaxSize for PhantomData<T> {
110 const MAX_SIZE: Option<usize> = Some(0);
111}
112
113impl ConstMaxSize for Infallible {
114 const MAX_SIZE: Option<usize> = Some(0);
115}
116
117impl ConstMaxSize for () {
118 const MAX_SIZE: Option<usize> = Some(0);
119}
120
121macro_rules! impl_tuple {
122 ($($t:ident),+) => {
123 impl<$($t: ConstMaxSize),+> ConstMaxSize for ($($t,)+) {
124 const MAX_SIZE: Option<usize> = {
125 let mut total: Option<usize> = Some(0);
126 $( total = max_size_add(total, $t::MAX_SIZE); )+
127 total
128 };
129 }
130 };
131}
132
133impl_tuple!(A);
134impl_tuple!(A, B);
135impl_tuple!(A, B, C);
136impl_tuple!(A, B, C, D);
137impl_tuple!(A, B, C, D, E);
138impl_tuple!(A, B, C, D, E, F);
139impl_tuple!(A, B, C, D, E, F, G);
140impl_tuple!(A, B, C, D, E, F, G, H);
141impl_tuple!(A, B, C, D, E, F, G, H, I);
142impl_tuple!(A, B, C, D, E, F, G, H, I, J);
143impl_tuple!(A, B, C, D, E, F, G, H, I, J, K);
144impl_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);
145
146impl<const MAX: u32> ConstMaxSize for BytesM<MAX> {
147 const MAX_SIZE: Option<usize> = max_size_opaque_variable(MAX);
148}
149
150impl<const MAX: u32> ConstMaxSize for StringM<MAX> {
151 const MAX_SIZE: Option<usize> = max_size_opaque_variable(MAX);
152}
153
154impl<const MAX: u32> ConstMaxSize for VecM<u8, MAX> {
155 const MAX_SIZE: Option<usize> = max_size_opaque_variable(MAX);
156}
157
158impl<T: ConstMaxSize + StaticIfNoAlloc, const MAX: u32> ConstMaxSize for VecM<T, MAX> {
163 const MAX_SIZE: Option<usize> = None;
164}
165
166#[cfg(test)]
167mod tests {
168 use super::ConstMaxSize;
169 use xdr_common::{BytesM, StringM, VecM};
170
171 const fn bound<T: ConstMaxSize>() -> Option<usize> {
172 T::MAX_SIZE
173 }
174
175 const _: () = assert!(matches!(bound::<u32>(), Some(5)));
177 const _: () = assert!(matches!(bound::<i64>(), Some(9)));
178 const _: () = assert!(matches!(bound::<bool>(), Some(1)));
179 const _: () = assert!(matches!(bound::<f32>(), Some(4)));
180 const _: () = assert!(matches!(bound::<u16>(), Some(3)));
181
182 const _: () = assert!(matches!(bound::<[u8; 5]>(), Some(5)));
184 const _: () = assert!(matches!(bound::<[u32; 3]>(), Some(15)));
186
187 const _: () = assert!(bound::<&'static u32>().is_none());
189 const _: () = assert!(bound::<&'static [u8]>().is_none());
190 const _: () = assert!(bound::<&'static str>().is_none());
191 const _: () = assert!(bound::<&'static [u32]>().is_none());
192
193 #[cfg(feature = "alloc")]
197 const _: () = assert!(bound::<alloc::boxed::Box<u32>>().is_none());
198 #[cfg(feature = "alloc")]
199 const _: () = assert!(bound::<alloc::boxed::Box<[u8; 4]>>().is_none());
200 #[cfg(feature = "alloc")]
201 const _: () = assert!(bound::<Option<alloc::boxed::Box<u32>>>().is_none());
202
203 #[cfg(feature = "alloc")]
207 struct Rec;
208 #[cfg(feature = "alloc")]
209 impl ConstMaxSize for Rec {
210 const MAX_SIZE: Option<usize> = <Option<alloc::boxed::Box<Rec>> as ConstMaxSize>::MAX_SIZE;
211 }
212 #[cfg(feature = "alloc")]
213 const _: () = assert!(bound::<Rec>().is_none());
214
215 const _: () = assert!(matches!(bound::<Option<u32>>(), Some(6)));
217 const _: () = assert!(bound::<Option<&'static u32>>().is_none());
218
219 const _: () = assert!(matches!(bound::<Result<u32, i64>>(), Some(10)));
221
222 const _: () = assert!(matches!(bound::<(u16, i16)>(), Some(6)));
224 const _: () = assert!(matches!(bound::<()>(), Some(0)));
225
226 const _: () = assert!(matches!(bound::<core::marker::PhantomData<u64>>(), Some(0)));
228 const _: () = assert!(matches!(bound::<core::convert::Infallible>(), Some(0)));
229
230 const _: () = assert!(matches!(bound::<[&'static [u8]; 0]>(), Some(0)));
232
233 const _: () = assert!(matches!(bound::<BytesM<16>>(), Some(17)));
235 const _: () = assert!(matches!(bound::<StringM<8>>(), Some(9)));
236 const _: () = assert!(matches!(bound::<VecM<u8, 4>>(), Some(5)));
237
238 const _: () = assert!(bound::<VecM<u32, 5>>().is_none());
240
241 #[cfg(target_pointer_width = "64")]
243 const _: () = assert!(matches!(
244 bound::<BytesM>(),
245 Some(n) if n == 5 + u32::MAX as usize
246 ));
247
248 #[cfg(feature = "int128")]
249 const _: () = assert!(matches!(bound::<i128>(), Some(18)));
250 #[cfg(feature = "int128")]
251 const _: () = assert!(matches!(bound::<u128>(), Some(18)));
252
253 #[test]
254 fn bounds_are_stable() {
255 assert_eq!(bound::<u32>(), Some(5));
257 assert_eq!(bound::<Option<u32>>(), Some(6));
258 assert_eq!(bound::<VecM<u32, 5>>(), None);
259 }
260}