aligned_bytes/
bytes.rs

1use crate::aligned_alloc;
2use crate::boxed::AlignedBox;
3
4use alloc::alloc::alloc_zeroed;
5use core::fmt::{self, Debug};
6use core::ops::{Deref, DerefMut};
7use core::slice;
8
9/// A continuous fixed-length byte array with a specified alignment.
10pub struct AlignedBytes {
11    inner: AlignedBox<[u8]>,
12}
13
14impl AlignedBytes {
15    /// Allocate a zero-initialized byte array with an exact alignment.
16    pub fn new_zeroed(len: usize, align: usize) -> Self {
17        let inner = unsafe {
18            let ptr = if len == 0 {
19                align as *mut u8
20            } else {
21                aligned_alloc(alloc_zeroed, len, align)
22            };
23            AlignedBox::from_raw(slice::from_raw_parts_mut(ptr, len), align)
24        };
25        debug_assert!(inner.as_ptr() as usize % align == 0);
26        Self { inner }
27    }
28
29    /// Returns the alignment of the byte array.
30    pub fn alignment(&self) -> usize {
31        AlignedBox::alignment(&self.inner)
32    }
33}
34
35impl Debug for AlignedBytes {
36    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37        <[u8] as Debug>::fmt(&**self, f)
38    }
39}
40
41impl Deref for AlignedBytes {
42    type Target = [u8];
43    fn deref(&self) -> &Self::Target {
44        &*self.inner
45    }
46}
47
48impl DerefMut for AlignedBytes {
49    fn deref_mut(&mut self) -> &mut Self::Target {
50        &mut *self.inner
51    }
52}
53
54impl AsRef<[u8]> for AlignedBytes {
55    fn as_ref(&self) -> &[u8] {
56        &*self
57    }
58}
59
60impl AsMut<[u8]> for AlignedBytes {
61    fn as_mut(&mut self) -> &mut [u8] {
62        &mut *self
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use super::AlignedBytes;
69
70    #[test]
71    fn check_alignment() {
72        let align = 4096;
73        let bytes = AlignedBytes::new_zeroed(8, align);
74        assert_eq!(bytes.alignment(), align);
75        assert!(bytes.as_ptr() as usize % align == 0);
76    }
77
78    #[should_panic(expected = "Invalid layout: size = 1, align = 0")]
79    #[test]
80    fn check_layout_zero_align() {
81        AlignedBytes::new_zeroed(1, 0);
82    }
83
84    #[should_panic(expected = "Invalid layout: size = 1, align = 3")]
85    #[test]
86    fn check_layout_align_not_power_of_2() {
87        AlignedBytes::new_zeroed(1, 3);
88    }
89
90    #[should_panic]
91    #[test]
92    fn check_layout_overflow() {
93        let size = core::mem::size_of::<usize>() * 8;
94        AlignedBytes::new_zeroed((1usize << (size - 1)) + 1, 1usize << (size - 1));
95    }
96
97    #[test]
98    fn check_markers() {
99        fn require_send<T: Send>() {}
100        fn require_sync<T: Sync>() {}
101
102        require_send::<AlignedBytes>();
103        require_sync::<AlignedBytes>();
104
105        #[cfg(feature = "std")]
106        {
107            use std::panic::{RefUnwindSafe, UnwindSafe};
108            fn require_unwind_safe<T: UnwindSafe>() {}
109            fn require_ref_unwind_safe<T: RefUnwindSafe>() {}
110            require_unwind_safe::<AlignedBytes>();
111            require_ref_unwind_safe::<AlignedBytes>();
112        }
113    }
114
115    #[test]
116    fn check_zst() {
117        AlignedBytes::new_zeroed(0, 2);
118    }
119}