Skip to main content

nuclei/buf/
aligned.rs

1//! [`AlignedBuf`]: a buffer whose memory starts at an address of the
2//! caller's chosen alignment, for a file opened for direct IO.
3
4use core::mem::MaybeUninit;
5use core::ptr::NonNull;
6use std::alloc::{self, Layout};
7use std::io;
8
9use super::owned::{IoBuf, IoBufMut};
10
11/// A buffer of a fixed capacity whose memory starts at an address that is
12/// a multiple of a chosen alignment: the buffer a file opened for direct IO
13/// (`O_DIRECT`, `FILE_FLAG_NO_BUFFERING`) is read into and written from by
14/// the owned calls ([`Handle::read_at_owned`](crate::io::Handle::read_at_owned),
15/// [`Handle::write_at_owned`](crate::io::Handle::write_at_owned) and the
16/// others), which hand its memory to the kernel as it is.
17///
18/// The kernel's alignment rules for direct IO ask the memory's address, the
19/// file offset and the length to be multiples of the device's logical block
20/// size (512 or 4096 bytes on most devices); a buffer aligned to 4096 with a
21/// capacity of a multiple of 4096 meets them on all of them.
22///
23/// It holds its first [`len`](Self::len) bytes, as a `Vec<u8>` does, and
24/// never grows past its capacity. Its memory is the caller's: it is not
25/// charged to the runtime's IO buffer cap.
26pub struct AlignedBuf {
27    ptr: NonNull<u8>,
28    len: usize,
29    layout: Layout,
30}
31
32// SAFETY: the buffer owns its memory, which nothing else points at.
33unsafe impl Send for AlignedBuf {}
34// SAFETY: shared, it is only read.
35unsafe impl Sync for AlignedBuf {}
36
37impl AlignedBuf {
38    /// An empty buffer with room for `capacity` bytes, its memory aligned to
39    /// `align` bytes.
40    ///
41    /// # Errors
42    ///
43    /// `InvalidInput` when `align` is not a power of two, or `capacity`
44    /// rounded up to it is past what memory can hold; `OutOfMemory` when
45    /// the allocator has no memory for it.
46    pub fn new(capacity: usize, align: usize) -> io::Result<Self> {
47        Self::alloc(capacity, align, false)
48    }
49
50    /// A buffer of `len` zeroed bytes, its memory aligned to `align` bytes,
51    /// with room for exactly `len`.
52    ///
53    /// # Errors
54    ///
55    /// As [`new`](Self::new).
56    pub fn zeroed(len: usize, align: usize) -> io::Result<Self> {
57        let mut buf = Self::alloc(len, align, true)?;
58        buf.len = len;
59        Ok(buf)
60    }
61
62    fn alloc(capacity: usize, align: usize, zeroed: bool) -> io::Result<Self> {
63        if !align.is_power_of_two() {
64            return Err(io::Error::new(
65                io::ErrorKind::InvalidInput,
66                "the alignment is not a power of two",
67            ));
68        }
69        let layout = Layout::from_size_align(capacity, align).map_err(|_| {
70            io::Error::new(
71                io::ErrorKind::InvalidInput,
72                "the buffer is larger than memory can hold",
73            )
74        })?;
75        if capacity == 0 {
76            return Ok(Self {
77                // An address of the alignment, never read or written through.
78                ptr: NonNull::new(core::ptr::without_provenance_mut(align))
79                    .unwrap_or(NonNull::dangling()),
80                len: 0,
81                layout,
82            });
83        }
84        // SAFETY: the layout's size is not zero.
85        let raw = unsafe {
86            if zeroed {
87                alloc::alloc_zeroed(layout)
88            } else {
89                alloc::alloc(layout)
90            }
91        };
92        let ptr = NonNull::new(raw).ok_or_else(|| {
93            io::Error::new(
94                io::ErrorKind::OutOfMemory,
95                "the allocator has no memory for the buffer",
96            )
97        })?;
98        Ok(Self {
99            ptr,
100            len: 0,
101            layout,
102        })
103    }
104
105    /// How many bytes it holds.
106    pub fn len(&self) -> usize {
107        self.len
108    }
109
110    /// Whether it holds no byte.
111    pub fn is_empty(&self) -> bool {
112        self.len == 0
113    }
114
115    /// How many bytes its memory has room for.
116    pub fn capacity(&self) -> usize {
117        self.layout.size()
118    }
119
120    /// The alignment of its memory's address.
121    pub fn alignment(&self) -> usize {
122        self.layout.align()
123    }
124
125    /// The address of its first byte.
126    pub fn as_ptr(&self) -> *const u8 {
127        self.ptr.as_ptr()
128    }
129
130    /// The address of its first byte, for writing.
131    pub fn as_mut_ptr(&mut self) -> *mut u8 {
132        self.ptr.as_ptr()
133    }
134
135    /// Holds no byte any more; the memory stays.
136    pub fn clear(&mut self) {
137        self.len = 0;
138    }
139
140    /// Keeps only its first `len` bytes (all of them if it holds fewer).
141    pub fn truncate(&mut self, len: usize) {
142        self.len = self.len.min(len);
143    }
144
145    /// Copies as much of `bytes` as its room holds onto its end and returns
146    /// how many: it never grows past its capacity.
147    pub fn extend_from_slice(&mut self, bytes: &[u8]) -> usize {
148        let n = bytes.len().min(self.capacity() - self.len);
149        // SAFETY: the `n` bytes after the first `len` are within the
150        // buffer's memory, which `bytes` cannot overlap (it is borrowed
151        // apart from `self`).
152        unsafe {
153            core::ptr::copy_nonoverlapping(bytes.as_ptr(), self.ptr.as_ptr().add(self.len), n);
154        }
155        self.len += n;
156        n
157    }
158
159    /// Its memory past the bytes it holds.
160    pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<u8>] {
161        // SAFETY: the memory holds `capacity` bytes, the buffer's own.
162        unsafe {
163            core::slice::from_raw_parts_mut(
164                self.ptr.as_ptr().add(self.len).cast::<MaybeUninit<u8>>(),
165                self.capacity() - self.len,
166            )
167        }
168    }
169
170    /// Sets how many bytes it holds to `len`.
171    ///
172    /// # Safety
173    ///
174    /// `len <= capacity()`, and the first `len` bytes are initialized.
175    pub unsafe fn set_len(&mut self, len: usize) {
176        self.len = len;
177    }
178}
179
180impl Default for AlignedBuf {
181    /// An empty buffer with no memory.
182    fn default() -> Self {
183        Self {
184            ptr: NonNull::dangling(),
185            len: 0,
186            layout: Layout::new::<()>(),
187        }
188    }
189}
190
191impl Drop for AlignedBuf {
192    fn drop(&mut self) {
193        if self.layout.size() != 0 {
194            // SAFETY: allocated with this layout by `alloc`, freed once.
195            unsafe { alloc::dealloc(self.ptr.as_ptr(), self.layout) };
196        }
197    }
198}
199
200impl core::ops::Deref for AlignedBuf {
201    type Target = [u8];
202
203    fn deref(&self) -> &[u8] {
204        // SAFETY: the first `len` bytes are initialized.
205        unsafe { core::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
206    }
207}
208
209impl core::ops::DerefMut for AlignedBuf {
210    fn deref_mut(&mut self) -> &mut [u8] {
211        // SAFETY: as for `deref`, and borrowed uniquely.
212        unsafe { core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
213    }
214}
215
216impl core::fmt::Debug for AlignedBuf {
217    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
218        f.debug_struct("AlignedBuf")
219            .field("len", &self.len)
220            .field("capacity", &self.capacity())
221            .field("alignment", &self.alignment())
222            .finish()
223    }
224}
225
226// SAFETY: the memory is the buffer's own heap allocation, which does not
227// move with the value; its first `len` bytes are initialized.
228unsafe impl IoBuf for AlignedBuf {
229    fn stable_ptr(&self) -> *const u8 {
230        self.as_ptr()
231    }
232
233    fn bytes_init(&self) -> usize {
234        self.len
235    }
236
237    fn bytes_total(&self) -> usize {
238        self.capacity()
239    }
240}
241
242// SAFETY: as for `IoBuf`; the whole capacity is writable.
243unsafe impl IoBufMut for AlignedBuf {
244    fn stable_mut_ptr(&mut self) -> *mut u8 {
245        self.as_mut_ptr()
246    }
247
248    unsafe fn set_init(&mut self, pos: usize) {
249        self.len = pos;
250    }
251}