Skip to main content

multiboot2_common/
bytes_ref.rs

1//! Module for [`BytesRef`].
2
3use crate::{ALIGNMENT, Header, MemoryError};
4use core::marker::PhantomData;
5use core::ops::Deref;
6
7/// Wraps a byte slice representing a Multiboot2 structure including an optional
8/// terminating padding, if necessary.
9///
10/// This type ensures that casts from the underlying bytes to a specific tag are
11/// either same-size or down-size casts, never invalid up-size casts. Instances
12/// guarantee that the memory requirements promised in the crate description
13/// are respected.
14#[derive(Clone, Debug, PartialEq, Eq)]
15#[repr(transparent)]
16pub struct BytesRef<'a, H: Header> {
17    bytes: &'a [u8],
18    // Ensure that consumers can rely on the size properties for `H` that
19    // already have been verified when this type was constructed.
20    _h: PhantomData<H>,
21}
22
23impl<'a, H: Header> TryFrom<&'a [u8]> for BytesRef<'a, H> {
24    type Error = MemoryError;
25
26    fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
27        if bytes.len() < size_of::<H>() {
28            return Err(MemoryError::ShorterThanHeader);
29        }
30        if bytes.as_ptr().align_offset(ALIGNMENT) != 0 {
31            return Err(MemoryError::WrongAlignment);
32        }
33        let padding_bytes = bytes.len() % ALIGNMENT;
34        if padding_bytes != 0 {
35            return Err(MemoryError::MissingPadding);
36        }
37        Ok(Self {
38            bytes,
39            _h: PhantomData,
40        })
41    }
42}
43
44impl<'a, H: Header> Deref for BytesRef<'a, H> {
45    type Target = &'a [u8];
46
47    fn deref(&self) -> &Self::Target {
48        &self.bytes
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55    use crate::test_utils::{AlignedBytes, DummyTestHeader};
56
57    #[test]
58    fn test_bytes_ref() {
59        let empty: &[u8] = &[];
60        assert_eq!(
61            BytesRef::<'_, DummyTestHeader>::try_from(empty),
62            Err(MemoryError::ShorterThanHeader)
63        );
64
65        let slice = &[0_u8, 1, 2, 3, 4, 5, 6];
66        assert_eq!(
67            BytesRef::<'_, DummyTestHeader>::try_from(&slice[..]),
68            Err(MemoryError::ShorterThanHeader)
69        );
70
71        let slice = AlignedBytes([0_u8, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0]);
72        // Guaranteed wrong alignment
73        let unaligned_slice = &slice[3..];
74        assert_eq!(
75            BytesRef::<'_, DummyTestHeader>::try_from(unaligned_slice),
76            Err(MemoryError::WrongAlignment)
77        );
78
79        let slice = AlignedBytes([0_u8, 1, 2, 3, 4, 5, 6, 7]);
80        let slice = &slice[..];
81        assert_eq!(
82            BytesRef::try_from(slice),
83            Ok(BytesRef {
84                bytes: slice,
85                _h: PhantomData::<DummyTestHeader>
86            })
87        );
88    }
89}