Skip to main content

bin_proto/impls/
array.rs

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}