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}