1use bitstream_io::{BitRead, BitWrite, Endianness};
2
3use crate::{util, BitDecode, BitEncode, Result};
4use core::mem::MaybeUninit;
5
6struct PartialGuard<T> {
7 ptr: *mut T,
8 len: usize,
9}
10
11impl<T> Drop for PartialGuard<T> {
12 fn drop(&mut self) {
13 unsafe {
14 core::ptr::drop_in_place(core::ptr::slice_from_raw_parts_mut(self.ptr, self.len));
15 }
16 }
17}
18
19impl<Ctx, T, const N: usize> BitDecode<Ctx> for [T; N]
20where
21 T: BitDecode<Ctx>,
22{
23 fn decode<R, E>(read: &mut R, ctx: &mut Ctx, (): ()) -> Result<Self>
24 where
25 R: BitRead,
26 E: Endianness,
27 {
28 let mut array: MaybeUninit<[T; N]> = MaybeUninit::uninit();
29 let mut guard = PartialGuard {
30 ptr: array.as_mut_ptr().cast::<T>(),
31 len: 0,
32 };
33 while guard.len < N {
34 let item = T::decode::<_, E>(read, ctx, ())?;
35 unsafe {
36 guard.ptr.add(guard.len).write(item);
37 }
38 guard.len += 1;
39 }
40 core::mem::forget(guard);
41 Ok(unsafe { array.assume_init() })
42 }
43}
44
45impl<Ctx, T, const N: usize> BitEncode<Ctx> for [T; N]
46where
47 T: BitEncode<Ctx> + Sized,
48{
49 fn encode<W, E>(&self, write: &mut W, ctx: &mut Ctx, (): ()) -> Result<()>
50 where
51 W: BitWrite,
52 E: Endianness,
53 {
54 util::encode_items::<_, E, _, _>(self.iter(), write, ctx)
55 }
56}
57
58test_codec!([u8; 4]; [0, 1, 2, 3] => [0x00, 0x01, 0x02, 0x03]);
59test_roundtrip!([u8; 4]);
60
61#[cfg(test)]
62mod test {
63 use core::cell::RefCell;
64
65 use bitstream_io::BigEndian;
66
67 use crate::{BitDecodeExt, Error};
68
69 use super::*;
70
71 #[derive(Default)]
72 struct MustDropState {
73 decoded: bool,
74 dropped: bool,
75 }
76
77 struct Ctx<'a>(&'a RefCell<MustDropState>);
78
79 struct MustDrop<'a>(&'a RefCell<MustDropState>);
80
81 impl<'a> Drop for MustDrop<'a> {
82 fn drop(&mut self) {
83 self.0.borrow_mut().dropped = true;
84 }
85 }
86
87 impl<'a> BitDecode<Ctx<'a>> for MustDrop<'a> {
88 fn decode<R, E>(_: &mut R, ctx: &mut Ctx<'a>, (): ()) -> Result<Self>
89 where
90 R: BitRead,
91 E: Endianness,
92 {
93 let mut state = ctx.0.borrow_mut();
94 if state.decoded {
95 Err(Error::Other(""))
96 } else {
97 state.decoded = true;
98 Ok(Self(ctx.0))
99 }
100 }
101 }
102
103 #[test]
104 fn partial_result_dropped() {
105 let state = RefCell::new(MustDropState::default());
106 assert!(<[MustDrop; 2]>::decode_bytes_ctx(&[], BigEndian, &mut Ctx(&state), ()).is_err());
107 assert!(state.borrow().dropped);
108 }
109}