Skip to main content

generic_array/ext_impls/
impl_bytecheck_0_8.rs

1use core::fmt;
2
3use bytecheck_0_8::{
4    rancor::{Fallible, ResultExt, Trace},
5    CheckBytes,
6};
7
8use crate::{ArrayLength, GenericArray};
9
10// Mirrors `bytecheck::ArrayCheckContext` and the `CheckBytes` impl for `[T; N]` in
11// `bytecheck-0.8/src/lib.rs`, renamed so the trace message identifies the type as a
12// `GenericArray`.
13#[derive(Debug)]
14struct GenericArrayCheckContext {
15    index: usize,
16}
17
18impl fmt::Display for GenericArrayCheckContext {
19    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20        write!(f, "while checking index '{}' of GenericArray", self.index)
21    }
22}
23
24// SAFETY: `check_bytes` only returns `Ok` if each element of the array is
25// valid. If each element of the array is valid then the whole array is also
26// valid.
27unsafe impl<T, N: ArrayLength, C> CheckBytes<C> for GenericArray<T, N>
28where
29    T: CheckBytes<C>,
30    C: Fallible + ?Sized,
31    C::Error: Trace,
32{
33    #[inline]
34    unsafe fn check_bytes(value: *const Self, context: &mut C) -> Result<(), C::Error> {
35        let base = value.cast::<T>();
36        for index in 0..N::USIZE {
37            // SAFETY: The caller has guaranteed that `value` points to enough
38            // bytes for this array and is properly aligned, so we can create
39            // pointers to each element and check them.
40            unsafe {
41                T::check_bytes(base.add(index), context)
42                    .with_trace(|| GenericArrayCheckContext { index })?;
43            }
44        }
45        Ok(())
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use bytecheck_0_8 as bytecheck;
52
53    use crate::typenum::{U0, U4};
54    use crate::{arr, GenericArray};
55    use bytecheck::check_bytes;
56    use bytecheck::rancor::Error;
57
58    #[test]
59    fn test_check_bytes_valid_u8() {
60        let array: GenericArray<u8, U4> = arr![1, 2, 3, 4];
61        // SAFETY: pointer is to an aligned, fully-initialized GenericArray<u8, U4>.
62        unsafe {
63            check_bytes::<GenericArray<u8, U4>, Error>(&array).unwrap();
64        }
65    }
66
67    #[test]
68    fn test_check_bytes_empty() {
69        let array: GenericArray<u8, U0> = arr![];
70        // SAFETY: empty arrays are always valid.
71        unsafe {
72            check_bytes::<GenericArray<u8, U0>, Error>(&array).unwrap();
73        }
74    }
75
76    #[test]
77    fn test_check_bytes_invalid_bool() {
78        // 0 and 1 are valid bool bit patterns; 2 is not.
79        let bytes: [u8; 4] = [1, 0, 1, 2];
80        let ptr = &bytes as *const [u8; 4] as *const GenericArray<bool, U4>;
81        // SAFETY: pointer is aligned (u8 == bool alignment) and points to 4 initialized bytes.
82        let result = unsafe { check_bytes::<GenericArray<bool, U4>, Error>(ptr) };
83        assert!(result.is_err());
84    }
85}