1#[cfg(feature = "alloc")]
26extern crate alloc;
27
28use core::ptr::NonNull;
29
30#[cfg(feature = "alloc")]
31use alloc::alloc::{alloc, alloc_zeroed, dealloc, Layout};
32
33pub const ALIGN: usize = 64;
36
37#[cfg(feature = "alloc")]
47pub struct AlignedBuffer {
48 ptr: NonNull<u8>,
49 len: usize,
50 cap: usize, }
52
53#[cfg(feature = "alloc")]
54impl AlignedBuffer {
55 pub(crate) fn new_uninit(len: usize) -> Self {
65 if len == 0 {
66 return Self {
67 ptr: NonNull::dangling(),
68 len: 0,
69 cap: 0,
70 };
71 }
72 let cap = Self::padded_cap(len);
73 let layout = Self::layout(cap);
74 let ptr = unsafe { alloc(layout) };
76 let ptr = NonNull::new(ptr).expect("allocation failed");
77 Self { ptr, len, cap }
78 }
79
80 pub fn zeroed(len: usize) -> Self {
82 if len == 0 {
83 return Self {
84 ptr: NonNull::dangling(),
85 len: 0,
86 cap: 0,
87 };
88 }
89 let cap = Self::padded_cap(len);
90 let layout = Self::layout(cap);
91 let ptr = unsafe { alloc_zeroed(layout) };
93 let ptr = NonNull::new(ptr).expect("allocation failed");
94 Self { ptr, len, cap }
95 }
96
97 pub fn from_slice(src: &[u8]) -> Self {
99 let mut buf = Self::new_uninit(src.len());
100 if !src.is_empty() {
101 buf.as_mut_slice().copy_from_slice(src);
102 }
103 buf
104 }
105
106 #[inline]
108 pub fn len(&self) -> usize {
109 self.len
110 }
111
112 #[inline]
114 pub fn is_empty(&self) -> bool {
115 self.len == 0
116 }
117
118 #[inline]
120 pub fn as_ptr(&self) -> *const u8 {
121 self.ptr.as_ptr()
122 }
123
124 #[inline]
126 pub fn as_mut_ptr(&mut self) -> *mut u8 {
127 self.ptr.as_ptr()
128 }
129
130 #[inline]
132 pub fn as_slice(&self) -> &[u8] {
133 unsafe { core::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
135 }
136
137 #[cfg(feature = "alloc")]
141 pub fn to_vec(&self) -> alloc::vec::Vec<u8> {
142 self.as_slice().to_vec()
143 }
144
145 #[cfg(feature = "alloc")]
149 pub fn into_vec(self) -> alloc::vec::Vec<u8> {
150 self.as_slice().to_vec()
151 }
152
153 #[inline]
155 pub fn as_mut_slice(&mut self) -> &mut [u8] {
156 unsafe { core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
158 }
159
160 pub fn fill(&mut self, val: u8) {
162 self.as_mut_slice().fill(val);
163 }
164
165 pub fn zero(&mut self) {
167 self.fill(0);
168 }
169
170 #[inline]
173 fn padded_cap(len: usize) -> usize {
174 (len + ALIGN - 1) & !(ALIGN - 1)
176 }
177
178 #[inline]
179 fn layout(cap: usize) -> Layout {
180 Layout::from_size_align(cap, ALIGN).expect("AlignedBuffer layout overflow")
181 }
182}
183
184#[cfg(feature = "alloc")]
187impl core::ops::Deref for AlignedBuffer {
188 type Target = [u8];
189 #[inline]
190 fn deref(&self) -> &[u8] {
191 self.as_slice()
192 }
193}
194
195#[cfg(feature = "alloc")]
196impl core::ops::DerefMut for AlignedBuffer {
197 #[inline]
198 fn deref_mut(&mut self) -> &mut [u8] {
199 self.as_mut_slice()
200 }
201}
202
203#[cfg(feature = "alloc")]
206impl Drop for AlignedBuffer {
207 fn drop(&mut self) {
208 if self.cap > 0 {
209 let layout = Self::layout(self.cap);
210 unsafe { dealloc(self.ptr.as_ptr(), layout) };
212 }
213 }
214}
215
216#[cfg(feature = "alloc")]
218unsafe impl Send for AlignedBuffer {}
219#[cfg(feature = "alloc")]
220unsafe impl Sync for AlignedBuffer {}
221
222#[cfg(feature = "alloc")]
225impl core::fmt::Debug for AlignedBuffer {
226 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
227 write!(
228 f,
229 "AlignedBuffer {{ len: {}, align: {ALIGN}, ptr: {:p} }}",
230 self.len,
231 self.as_ptr()
232 )
233 }
234}
235
236#[cfg(feature = "alloc")]
237impl Clone for AlignedBuffer {
238 fn clone(&self) -> Self {
239 Self::from_slice(self.as_slice())
240 }
241}
242
243#[cfg(test)]
246#[cfg(feature = "alloc")]
247mod tests {
248 use super::*;
249
250 #[test]
251 fn alignment_guarantee() {
252 for len in [1usize, 15, 16, 63, 64, 65, 1024, 65536] {
253 let buf = AlignedBuffer::zeroed(len);
254 assert_eq!(
255 buf.as_ptr() as usize % ALIGN,
256 0,
257 "len={len}: pointer not {ALIGN}-byte aligned"
258 );
259 assert_eq!(buf.len(), len);
260 }
261 }
262
263 #[test]
264 fn zero_size() {
265 let buf = AlignedBuffer::zeroed(0);
266 assert!(buf.is_empty());
267 assert_eq!(buf.len(), 0);
268 }
269
270 #[test]
271 fn from_slice_roundtrip() {
272 let data: Vec<u8> = (0u8..128).collect();
273 let buf = AlignedBuffer::from_slice(&data);
274 assert_eq!(buf.as_ptr() as usize % ALIGN, 0);
275 assert_eq!(buf.as_slice(), data.as_slice());
276 }
277
278 #[test]
279 fn clone_is_independent() {
280 let mut a = AlignedBuffer::from_slice(&[1u8, 2, 3, 4]);
281 let b = a.clone();
282 a.as_mut_slice()[0] = 0xFF;
283 assert_eq!(b.as_slice()[0], 1); }
285
286 #[test]
287 fn deref_works_with_kernel() {
288 let x = AlignedBuffer::from_slice(&[0x42u8; 64]);
289 let mut y = AlignedBuffer::zeroed(64);
290 crate::kernel::axpy(0x03, &x, &mut y);
292 let mut y_ref = vec![0u8; 64];
294 crate::kernel::scalar::axpy(0x03, &x, &mut y_ref);
295 assert_eq!(y.as_slice(), y_ref.as_slice());
296 }
297}