1#[allow(unused)]
2macro_rules! impl_read_list {
3 (
4 $ty:ident<T $(: $tbound0:ident $(+ $tbound1:ident)?)?
5 $(, $h:ident: $hbound0:ident + $hbound1:ident)?>,
6 $new:expr,
7 $push:ident
8 ) => {
9 impl<Tag, Ctx, T, $($h)?> $crate::BitDecode<Ctx, $crate::Tag<Tag>> for $ty<T, $($h)?>
10 where
11 T: $crate::BitDecode<Ctx> $(+ $tbound0 $(+ $tbound1)?)?,
12 Tag: ::core::convert::TryInto<usize>,
13 $($h: $hbound0 + $hbound1)?
14 {
15 fn decode<R, E>(
16 read: &mut R,
17 ctx: &mut Ctx,
18 tag: $crate::Tag<Tag>,
19 ) -> $crate::Result<Self>
20 where
21 R: ::bitstream_io::BitRead,
22 E: ::bitstream_io::Endianness,
23 {
24 let item_count = ::core::convert::TryInto::try_into(tag.0)
25 .map_err(|_| $crate::Error::TagConvert)?;
26 let mut this = ($new)(item_count);
27 for _ in 0..item_count {
28 this.$push($crate::BitDecode::<_, _>::decode::<_, E>(read, ctx, ())?);
29 }
30 ::core::result::Result::Ok(this)
31 }
32 }
33
34 impl<Ctx, T, $($h)?> $crate::BitDecode<Ctx, $crate::Untagged> for $ty<T, $($h)?>
35 where
36 T: $crate::BitDecode<Ctx> $(+ $tbound0 $(+ $tbound1)?)?,
37 $($h: $hbound0 + $hbound1)?
38 {
39 fn decode<R, E>(
40 read: &mut R,
41 ctx: &mut Ctx,
42 _: $crate::Untagged,
43 ) -> $crate::Result<Self>
44 where
45 R: ::bitstream_io::BitRead,
46 E: ::bitstream_io::Endianness,
47 {
48 $crate::util::decode_items_to_eof::<_, E, _, _>(read, ctx).collect()
49 }
50 }
51
52 #[cfg(feature = "prepend-tags")]
53 impl<Ctx, T, $($h)?> $crate::BitDecode<Ctx> for $ty<T, $($h)?>
54 where
55 T: $crate::BitDecode<Ctx> $(+ $tbound0 $(+ $tbound1)?)?,
56 $($h: $hbound0 + $hbound1)?
57 {
58 fn decode<R, E>(
59 read: &mut R,
60 ctx: &mut Ctx,
61 (): (),
62 ) -> $crate::Result<Self>
63 where
64 R: ::bitstream_io::BitRead,
65 E: ::bitstream_io::Endianness,
66 {
67 let tag: usize = $crate::BitDecode::decode::<_, E>(read, ctx, ())?;
68 $crate::BitDecode::decode::<_, E>(read, ctx, $crate::Tag(tag))
69 }
70 }
71 }
72}
73
74#[allow(unused)]
75macro_rules! impl_write_list {
76 ($ty:ident<T $(: $tbound0:ident $(+ $tbound1:ident)?)? $(, $h:ident)?> ) => {
77 impl<Ctx, T, $($h)?> $crate::BitEncode<Ctx, $crate::Untagged> for $ty<T, $($h)?>
78 where
79 T: $crate::BitEncode<Ctx> $(+ $tbound0 $(+ $tbound1)?)?
80 {
81 fn encode<W, E>(&self,
82 write: &mut W,
83 ctx: &mut Ctx,
84 _: $crate::Untagged,
85 ) -> $crate::Result<()>
86 where
87 W: ::bitstream_io::BitWrite,
88 E: ::bitstream_io::Endianness,
89 {
90 $crate::util::encode_items::<_, E, _, _>(self.iter(), write, ctx)
91 }
92 }
93
94 #[cfg(feature = "prepend-tags")]
95 impl<Ctx, T, $($h)?> $crate::BitEncode<Ctx> for $ty<T, $($h)?>
96 where
97 T: $crate::BitEncode<Ctx> $(+ $tbound0 $(+ $tbound1)?)?
98 {
99 fn encode<W, E>(&self,
100 write: &mut W,
101 ctx: &mut Ctx,
102 (): (),
103 ) -> $crate::Result<()>
104 where
105 W: ::bitstream_io::BitWrite,
106 E: ::bitstream_io::Endianness,
107 {
108 $crate::BitEncode::encode::<_, E>(&self.len(), write, ctx, ())?;
109 $crate::BitEncode::encode::<_, E>(self, write, ctx, $crate::Untagged)
110 }
111 }
112 }
113}
114
115#[cfg(feature = "alloc")]
116mod vec {
117 use alloc::vec::Vec;
118
119 impl_read_list!(Vec<T>, |n| Self::with_capacity(n), push);
120 impl_write_list!(Vec<T>);
121
122 #[cfg(test)]
123 mod tests {
124 use crate::{Tag, Untagged};
125
126 use super::*;
127
128 test_untagged_and_codec!(
129 Vec<u8>| Untagged, Tag(3); alloc::vec![1, 2, 3] => [0x01, 0x02, 0x03]
130 );
131
132 #[cfg(feature = "prepend-tags")]
133 test_roundtrip!(Vec::<i32>);
134 }
135}
136
137#[cfg(feature = "alloc")]
138mod linked_list {
139 use alloc::collections::linked_list::LinkedList;
140
141 impl_read_list!(LinkedList<T>, |_| Self::new(), push_back);
142 impl_write_list!(LinkedList<T>);
143
144 #[cfg(test)]
145 mod tests {
146 use crate::{Tag, Untagged};
147
148 use super::*;
149
150 test_untagged_and_codec!(
151 LinkedList<u8>| Untagged, Tag(3); [1, 2, 3].into() => [0x01, 0x02, 0x03]
152 );
153
154 #[cfg(feature = "prepend-tags")]
155 test_roundtrip!(LinkedList::<i32>);
156 }
157}
158
159#[cfg(feature = "alloc")]
160mod vec_deque {
161 use alloc::collections::vec_deque::VecDeque;
162
163 impl_read_list!(VecDeque<T>, |n| Self::with_capacity(n), push_back);
164 impl_write_list!(VecDeque<T>);
165
166 #[cfg(test)]
167 mod tests {
168 use crate::{Tag, Untagged};
169
170 use super::*;
171
172 test_untagged_and_codec!(
173 VecDeque<u8>| Untagged, Tag(3); [1, 2, 3].into() => [0x01, 0x02, 0x03]
174 );
175
176 #[cfg(feature = "prepend-tags")]
177 test_roundtrip!(VecDeque::<i32>);
178 }
179}
180
181#[cfg(feature = "alloc")]
182mod b_tree_set {
183 use alloc::collections::btree_set::BTreeSet;
184
185 impl_read_list!(BTreeSet<T: Ord>, |_| Self::new(), insert);
186 impl_write_list!(BTreeSet<T: Ord>);
187
188 #[cfg(test)]
189 mod tests {
190 use crate::{Tag, Untagged};
191
192 use super::*;
193
194 test_untagged_and_codec!(
195 BTreeSet<u8>| Untagged, Tag(3); [1, 2, 3].into() => [0x01, 0x02, 0x03]
196 );
197
198 #[cfg(feature = "prepend-tags")]
199 test_roundtrip!(BTreeSet::<i32>);
200 }
201}
202
203#[cfg(feature = "alloc")]
204mod binary_heap {
205 use alloc::collections::binary_heap::BinaryHeap;
206
207 impl_read_list!(BinaryHeap<T: Ord>, |n| Self::with_capacity(n), push);
208 impl_write_list!(BinaryHeap<T: Ord>);
209
210 #[cfg(test)]
211 mod tests {
212 use alloc::vec::Vec;
213
214 use bitstream_io::{BigEndian, BitReader};
215
216 use crate::{BitDecode, Tag, Untagged};
217
218 use super::*;
219
220 #[test]
221 fn decode() {
222 let bytes: &[u8] = &[0x01];
223 let exp: BinaryHeap<u8> = [1].into();
224 let read: BinaryHeap<u8> = BitDecode::decode::<_, BigEndian>(
225 &mut BitReader::endian(bytes, BigEndian),
226 &mut (),
227 Tag(1),
228 )
229 .unwrap();
230 assert_eq!(
231 exp.into_iter().collect::<Vec<_>>(),
232 read.into_iter().collect::<Vec<_>>()
233 );
234 }
235
236 test_encode!(BinaryHeap<u8>| Untagged; [1].into() => [0x01]);
237 }
238}
239
240#[cfg(feature = "std")]
241mod hash_set {
242 use core::hash::{BuildHasher, Hash};
243 use std::collections::HashSet;
244
245 impl_read_list!(HashSet<T: Hash + Eq, H: BuildHasher + Default>, |n| Self::with_capacity_and_hasher(n, H::default()), insert);
246 impl_write_list!(HashSet<T: Hash + Eq, H>);
247
248 #[cfg(test)]
249 mod tests {
250 use crate::{Tag, Untagged};
251
252 use super::*;
253
254 test_untagged_and_codec!(HashSet<u8>| Untagged, Tag(1); [1].into() => [0x01]);
255
256 #[cfg(feature = "prepend-tags")]
257 test_roundtrip!(HashSet::<i32>);
258 }
259}