1#[cfg(feature = "alloc")]
2use alloc::vec::Vec;
3#[cfg(feature = "std")]
4use std::io::{self, Cursor};
5
6use bitstream_io::{BitRead, BitReader, BitWrite, BitWriter, Endianness};
7#[cfg(not(feature = "std"))]
8use core2::io::{self, Cursor};
9
10use crate::{Error, Result};
11
12pub trait BitDecode<Ctx = (), Tag = ()>: Sized {
14 fn decode<R, E>(read: &mut R, ctx: &mut Ctx, tag: Tag) -> Result<Self>
16 where
17 R: BitRead,
18 E: Endianness;
19}
20
21pub trait BitDecodeExt<Ctx = (), Tag = ()>:
23 BitDecode<Ctx, Tag> + bit_decode::Sealed<Ctx, Tag>
24{
25 fn decode_bytes_ctx<E>(
29 bytes: &[u8],
30 byte_order: E,
31 ctx: &mut Ctx,
32 tag: Tag,
33 ) -> Result<(Self, u64)>
34 where
35 E: Endianness,
36 {
37 let mut buffer = BitReader::endian(io::Cursor::new(bytes), byte_order);
38 let this = Self::decode::<_, E>(&mut buffer, ctx, tag)?;
39 Ok((this, buffer.position_in_bits()?))
40 }
41
42 fn decode_all_bytes_ctx<E>(bytes: &[u8], byte_order: E, ctx: &mut Ctx, tag: Tag) -> Result<Self>
45 where
46 E: Endianness,
47 {
48 let (decoded, read_bits) = Self::decode_bytes_ctx(bytes, byte_order, ctx, tag)?;
49 let available_bits = u64::try_from(bytes.len())? * 8;
50 if read_bits == available_bits {
51 Ok(decoded)
52 } else {
53 Err(Error::Underrun {
54 read_bits,
55 available_bits,
56 })
57 }
58 }
59}
60
61impl<T, Ctx, Tag> BitDecodeExt<Ctx, Tag> for T where
62 T: BitDecode<Ctx, Tag> + bit_decode::Sealed<Ctx, Tag>
63{
64}
65
66pub trait BitEncode<Ctx = (), Tag = ()> {
68 fn encode<W, E>(&self, write: &mut W, ctx: &mut Ctx, tag: Tag) -> Result<()>
70 where
71 W: BitWrite,
72 E: Endianness;
73}
74
75pub trait BitEncodeExt<Ctx = (), Tag = ()>:
77 BitEncode<Ctx, Tag> + bit_encode::Sealed<Ctx, Tag>
78{
79 #[cfg(feature = "alloc")]
81 fn encode_bytes_ctx<E>(&self, byte_order: E, ctx: &mut Ctx, tag: Tag) -> Result<Vec<u8>>
82 where
83 E: Endianness,
84 {
85 let mut data = Vec::new();
86 let mut writer = BitWriter::endian(&mut data, byte_order);
87 self.encode::<_, E>(&mut writer, ctx, tag)?;
88 writer.byte_align()?;
89
90 Ok(data)
91 }
92
93 fn encode_bytes_ctx_buf<E>(
97 &self,
98 byte_order: E,
99 ctx: &mut Ctx,
100 tag: Tag,
101 buf: &mut [u8],
102 ) -> Result<u64>
103 where
104 E: Endianness,
105 {
106 let mut cursor = Cursor::new(buf);
107 let mut writer = BitWriter::endian(&mut cursor, byte_order);
108 self.encode::<_, E>(&mut writer, ctx, tag)?;
109 writer.byte_align()?;
110
111 Ok(cursor.position())
112 }
113}
114
115impl<T, Ctx, Tag> BitEncodeExt<Ctx, Tag> for T where
116 T: BitEncode<Ctx, Tag> + bit_encode::Sealed<Ctx, Tag>
117{
118}
119
120pub trait BitCodec: BitDecode + BitEncode + bit_codec::Sealed {
122 fn decode_bytes<E>(bytes: &[u8], byte_order: E) -> Result<(Self, u64)>
126 where
127 E: Endianness,
128 {
129 Self::decode_bytes_ctx(bytes, byte_order, &mut (), ())
130 }
131
132 fn decode_all_bytes<E>(bytes: &[u8], byte_order: E) -> Result<Self>
134 where
135 E: Endianness,
136 {
137 Self::decode_all_bytes_ctx(bytes, byte_order, &mut (), ())
138 }
139
140 #[cfg(feature = "alloc")]
142 fn encode_bytes<E>(&self, byte_order: E) -> Result<Vec<u8>>
143 where
144 E: Endianness,
145 {
146 self.encode_bytes_ctx(byte_order, &mut (), ())
147 }
148
149 fn encode_bytes_buf<E>(&self, byte_order: E, buf: &mut [u8]) -> Result<u64>
153 where
154 E: Endianness,
155 {
156 self.encode_bytes_ctx_buf(byte_order, &mut (), (), buf)
157 }
158}
159
160impl<T> BitCodec for T where T: BitDecode + BitEncode + bit_codec::Sealed {}
161
162mod bit_encode {
163 use super::BitEncode;
164
165 pub trait Sealed<Ctx, Tag> {}
166
167 impl<Ctx, Tag, T> Sealed<Ctx, Tag> for T where T: BitEncode<Ctx, Tag> {}
168}
169
170mod bit_decode {
171 use super::BitDecode;
172
173 pub trait Sealed<Ctx, Tag> {}
174
175 impl<Ctx, Tag, T> Sealed<Ctx, Tag> for T where T: BitDecode<Ctx, Tag> {}
176}
177
178mod bit_codec {
179 use super::{BitDecode, BitEncode};
180
181 pub trait Sealed {}
182
183 impl<T> Sealed for T where T: BitDecode + BitEncode {}
184}
185
186macro_rules! test_decode {
187 ($ty:ty | $tag:expr; $bytes:expr => $exp:expr) => {
188 #[cfg(test)]
189 #[test]
190 fn decode() {
191 let bytes: &[u8] = &$bytes;
192 let exp: $ty = $exp;
193 let read: $ty = $crate::BitDecode::<(), _>::decode::<_, ::bitstream_io::BigEndian>(
194 &mut ::bitstream_io::BitReader::endian(bytes, ::bitstream_io::BigEndian),
195 &mut (),
196 $tag,
197 )
198 .unwrap();
199 assert_eq!(exp, read);
200 }
201 };
202 ($ty:ty; $bytes:expr => $exp:expr) => {
203 #[cfg(test)]
204 #[test]
205 fn decode() {
206 let bytes: &[u8] = &$bytes;
207 let exp: $ty = $exp;
208 let decoded: $ty = $crate::BitDecode::decode::<_, ::bitstream_io::BigEndian>(
209 &mut ::bitstream_io::BitReader::endian(bytes, ::bitstream_io::BigEndian),
210 &mut (),
211 (),
212 )
213 .unwrap();
214 assert_eq!(exp, decoded);
215 }
216 };
217}
218
219macro_rules! test_encode {
220 ($ty:ty $(| $tag:expr)?; $value:expr => $exp:expr) => {
221 #[cfg(test)]
222 #[test]
223 fn encode() {
224 use $crate::BitEncode;
225
226 let exp: &[u8] = &$exp;
227 let value: $ty = $value;
228
229 #[cfg(feature = "alloc")]
230 {
231 let mut buffer: ::alloc::vec::Vec<u8> = ::alloc::vec::Vec::new();
232 value
233 .encode::<_, ::bitstream_io::BigEndian>(
234 &mut ::bitstream_io::BitWriter::endian(&mut buffer, ::bitstream_io::BigEndian),
235 &mut (),
236 ($($tag)?),
237 )
238 .unwrap();
239 assert_eq!(exp, &buffer);
240 }
241
242 #[cfg(not(feature = "alloc"))]
243 {
244 let mut buffer = [0u8; 16];
245 value
246 .encode::<_, ::bitstream_io::BigEndian>(
247 &mut ::bitstream_io::BitWriter::endian(&mut ::core2::io::Cursor::new(buffer.as_mut_slice()), ::bitstream_io::BigEndian),
248 &mut (),
249 ($($tag)?),
250 )
251 .unwrap();
252 assert_eq!(exp, &buffer[..exp.len()]);
253 assert!(::core::iter::Iterator::all(
254 &mut ::core::iter::IntoIterator::into_iter(&buffer[exp.len()..]),
255 |x| *x == 0)
256 );
257 }
258 }
259 };
260}
261
262macro_rules! test_codec {
263 ($ty:ty$(| $tag_write:expr, $tag_read:expr)?; $value:expr => $bytes:expr) => {
264 test_decode!($ty$(| $tag_read)?; $bytes => $value);
265 test_encode!($ty$(| $tag_write)?; $value => $bytes);
266 }
267}
268
269macro_rules! test_roundtrip {
270 ($ty:ty) => {
271 #[cfg(all(test, feature = "alloc"))]
272 ::proptest::proptest!(
273 #[test]
274 fn roundtrip(x in ::proptest::arbitrary::any::<$ty>()) {
275 let encoded = $crate::BitEncodeExt::encode_bytes_ctx(&x, ::bitstream_io::BigEndian, &mut (), ()).unwrap();
276 let decoded = <$ty as $crate::BitDecodeExt>::decode_bytes_ctx(&encoded, ::bitstream_io::BigEndian, &mut (), ()).unwrap().0;
277 ::proptest::prop_assert_eq!(x, decoded);
278 }
279 );
280 }
281}
282
283#[allow(unused)]
284macro_rules! test_untagged_and_codec {
285 ($ty:ty | $tag_write:expr, $tag_read:expr; $value:expr => $bytes:expr) => {
286 test_codec!($ty | $tag_write, $tag_read; $value => $bytes);
287 #[cfg(test)]
288 mod untagged {
289 use super::*;
290
291 test_decode!($ty| $crate::Untagged; $bytes => $value);
292 }
293 }
294}