Skip to main content

serde_shape/impls/
container.rs

1// Copyright 2026 FastLabs Developers
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use alloc::boxed::Box;
16use alloc::collections::BTreeMap;
17use alloc::collections::BTreeSet;
18use alloc::collections::BinaryHeap;
19use alloc::collections::LinkedList;
20use alloc::collections::VecDeque;
21use alloc::vec::Vec;
22#[cfg(feature = "std")]
23use core::hash::BuildHasher;
24#[cfg(feature = "std")]
25use core::hash::Hash;
26
27use crate::DeserializeShape;
28use crate::DeserializeShapeContext;
29use crate::SerializeShape;
30use crate::SerializeShapeContext;
31use crate::ShapeRef;
32
33impl<T> SerializeShape for Option<T>
34where
35    T: SerializeShape,
36{
37    fn serialize_shape_in(context: &mut SerializeShapeContext) -> ShapeRef {
38        ShapeRef::Option(Box::new(T::serialize_shape_in(context)))
39    }
40}
41
42impl<T> DeserializeShape for Option<T>
43where
44    T: DeserializeShape,
45{
46    fn deserialize_shape_in(context: &mut DeserializeShapeContext) -> ShapeRef {
47        ShapeRef::Option(Box::new(T::deserialize_shape_in(context)))
48    }
49}
50
51macro_rules! seq_shape {
52    (
53        $(
54            ($($generics:tt)*) $ty:ty
55            where
56                serialize { $($serialize_bounds:tt)* }
57                deserialize { $($deserialize_bounds:tt)* }
58            => $item:ty;
59        )+
60    ) => {
61        $(
62            impl<$($generics)*> SerializeShape for $ty
63            where
64                $($serialize_bounds)*
65            {
66                fn serialize_shape_in(context: &mut SerializeShapeContext) -> ShapeRef {
67                    ShapeRef::Seq(Box::new(<$item as SerializeShape>::serialize_shape_in(context)))
68                }
69            }
70
71            impl<$($generics)*> DeserializeShape for $ty
72            where
73                $($deserialize_bounds)*
74            {
75                fn deserialize_shape_in(context: &mut DeserializeShapeContext) -> ShapeRef {
76                    ShapeRef::Seq(Box::new(<$item as DeserializeShape>::deserialize_shape_in(context)))
77                }
78            }
79        )+
80    };
81}
82
83seq_shape! {
84    (T) Vec<T>
85    where
86        serialize { T: SerializeShape }
87        deserialize { T: DeserializeShape }
88    => T;
89
90    (T) VecDeque<T>
91    where
92        serialize { T: SerializeShape }
93        deserialize { T: DeserializeShape }
94    => T;
95
96    (T) LinkedList<T>
97    where
98        serialize { T: SerializeShape }
99        deserialize { T: DeserializeShape }
100    => T;
101
102    (T) BinaryHeap<T>
103    where
104        serialize { T: SerializeShape }
105        deserialize { T: Ord + DeserializeShape }
106    => T;
107
108    (T) BTreeSet<T>
109    where
110        serialize { T: SerializeShape }
111        deserialize { T: DeserializeShape + Ord }
112    => T;
113
114}
115
116impl<T> SerializeShape for [T]
117where
118    T: SerializeShape,
119{
120    fn serialize_shape_in(context: &mut SerializeShapeContext) -> ShapeRef {
121        ShapeRef::Seq(Box::new(T::serialize_shape_in(context)))
122    }
123}
124
125#[cfg(feature = "std")]
126seq_shape! {
127    (T, S) std::collections::HashSet<T, S>
128    where
129        serialize { T: SerializeShape }
130        deserialize {
131            T: DeserializeShape + Eq + Hash,
132            S: BuildHasher + Default
133        }
134    => T;
135}
136
137impl<T> SerializeShape for [T; 0] {
138    fn serialize_shape_in(_context: &mut SerializeShapeContext) -> ShapeRef {
139        ShapeRef::Array {
140            item: Box::new(unobserved_empty_array_item::<T>()),
141            len: 0,
142        }
143    }
144}
145
146impl<T> DeserializeShape for [T; 0] {
147    fn deserialize_shape_in(_context: &mut DeserializeShapeContext) -> ShapeRef {
148        ShapeRef::Array {
149            item: Box::new(unobserved_empty_array_item::<T>()),
150            len: 0,
151        }
152    }
153}
154
155fn unobserved_empty_array_item<T>() -> ShapeRef {
156    ShapeRef::Opaque(crate::OpaqueShape {
157        type_name: core::any::type_name::<T>(),
158        reason: crate::OpaqueReason::Unobserved,
159        detail: Some("zero-length array has no elements"),
160    })
161}
162
163macro_rules! array_shape {
164    ($($len:literal)+) => {
165        $(
166            impl<T> SerializeShape for [T; $len]
167            where
168                T: SerializeShape,
169            {
170                fn serialize_shape_in(context: &mut SerializeShapeContext) -> ShapeRef {
171                    ShapeRef::Array {
172                        item: Box::new(T::serialize_shape_in(context)),
173                        len: $len,
174                    }
175                }
176            }
177
178            impl<T> DeserializeShape for [T; $len]
179            where
180                T: DeserializeShape,
181            {
182                fn deserialize_shape_in(context: &mut DeserializeShapeContext) -> ShapeRef {
183                    ShapeRef::Array {
184                        item: Box::new(T::deserialize_shape_in(context)),
185                        len: $len,
186                    }
187                }
188            }
189        )+
190    };
191}
192
193array_shape! {
194    1 2 3 4 5 6 7 8 9 10
195    11 12 13 14 15 16 17 18 19 20
196    21 22 23 24 25 26 27 28 29 30
197    31 32
198}
199
200macro_rules! map_shape {
201    (
202        $(
203            ($($generics:tt)*) $ty:ty
204            where
205                serialize { $($serialize_bounds:tt)* }
206                deserialize { $($deserialize_bounds:tt)* }
207            => ($key:ty, $value:ty);
208        )+
209    ) => {
210        $(
211            impl<$($generics)*> SerializeShape for $ty
212            where
213                $($serialize_bounds)*
214            {
215                fn serialize_shape_in(context: &mut SerializeShapeContext) -> ShapeRef {
216                    ShapeRef::Map {
217                        key: Box::new(<$key as SerializeShape>::serialize_shape_in(context)),
218                        value: Box::new(<$value as SerializeShape>::serialize_shape_in(context)),
219                    }
220                }
221            }
222
223            impl<$($generics)*> DeserializeShape for $ty
224            where
225                $($deserialize_bounds)*
226            {
227                fn deserialize_shape_in(context: &mut DeserializeShapeContext) -> ShapeRef {
228                    ShapeRef::Map {
229                        key: Box::new(<$key as DeserializeShape>::deserialize_shape_in(context)),
230                        value: Box::new(<$value as DeserializeShape>::deserialize_shape_in(context)),
231                    }
232                }
233            }
234        )+
235    };
236}
237
238map_shape! {
239    (K, V) BTreeMap<K, V>
240    where
241        serialize {
242            K: SerializeShape,
243            V: SerializeShape
244        }
245        deserialize {
246            K: DeserializeShape + Ord,
247            V: DeserializeShape
248        }
249    => (K, V);
250
251}
252
253#[cfg(feature = "std")]
254map_shape! {
255    (K, V, S) std::collections::HashMap<K, V, S>
256    where
257        serialize {
258            K: SerializeShape,
259            V: SerializeShape
260        }
261        deserialize {
262            K: DeserializeShape + Eq + Hash,
263            V: DeserializeShape,
264            S: BuildHasher + Default
265        }
266    => (K, V);
267}