1#![cfg_attr(docsrs, feature(doc_cfg))]
2
3mod error;
7
8use std::{
9 alloc::{Layout, LayoutError, alloc, alloc_zeroed, dealloc, handle_alloc_error},
10 fmt::{Debug, Formatter, Result as FmtResult},
11 mem::ManuallyDrop,
12 ops::{Deref, DerefMut},
13 ptr::{NonNull, copy_nonoverlapping},
14 slice::{from_raw_parts, from_raw_parts_mut},
15};
16
17use Error::{AllocFailed, Overflow};
18use compio_buf::{IoBuf, IoBufMut, SetBufInit};
19pub use error::{Error, Result};
20
21pub const PAGE_SIZE: usize = 4096;
23
24pub const ALIGNMENT: usize = 4096;
26
27const ALIGN_MASK: usize = ALIGNMENT - 1;
29
30static PAGE_LAYOUT: Layout = unsafe { Layout::from_size_align_unchecked(PAGE_SIZE, ALIGNMENT) };
33
34#[inline(always)]
36fn layout(size: usize) -> std::result::Result<Layout, LayoutError> {
37 if size == PAGE_SIZE {
38 Ok(PAGE_LAYOUT)
39 } else {
40 Layout::from_size_align(size, ALIGNMENT)
41 }
42}
43
44#[inline(always)]
47fn layout_unchecked(cap: usize) -> Layout {
48 if cap == PAGE_SIZE {
49 PAGE_LAYOUT
50 } else {
51 unsafe { Layout::from_size_align_unchecked(cap, ALIGNMENT) }
52 }
53}
54
55pub struct AlignedBuf {
62 ptr: NonNull<u8>,
63 len: usize,
64 cap: usize,
65}
66
67unsafe impl Send for AlignedBuf {}
68unsafe impl Sync for AlignedBuf {}
69
70impl AlignedBuf {
71 #[inline]
74 pub fn with_cap(cap: usize) -> Result<Self> {
75 let cap = cap.max(PAGE_SIZE);
76 let lo = layout(cap)?;
77 let ptr = unsafe { alloc(lo) };
78 let ptr = NonNull::new(ptr).ok_or(AllocFailed)?;
79 Ok(Self { ptr, len: 0, cap })
80 }
81
82 #[inline]
85 pub fn zeroed(size: usize) -> Result<Self> {
86 let cap = size.max(PAGE_SIZE);
87 let lo = layout(cap)?;
88 let ptr = unsafe { alloc_zeroed(lo) };
89 let ptr = NonNull::new(ptr).ok_or(AllocFailed)?;
90 Ok(Self {
91 ptr,
92 len: size,
93 cap,
94 })
95 }
96
97 #[inline]
100 pub fn page() -> Result<Self> {
101 let ptr = unsafe { alloc_zeroed(PAGE_LAYOUT) };
102 let ptr = NonNull::new(ptr).ok_or(AllocFailed)?;
103 Ok(Self {
104 ptr,
105 len: PAGE_SIZE,
106 cap: PAGE_SIZE,
107 })
108 }
109
110 pub unsafe fn slice_into_raws(&self, chunk: usize) -> impl Iterator<Item = RawIoBuf> + '_ {
115 debug_assert!(
116 chunk > 0 && (chunk & ALIGN_MASK) == 0,
117 "chunk alignment mismatch"
118 );
119 let count = self.cap / chunk;
120 let base = self.ptr.as_ptr();
121 (0..count).map(move |i| unsafe { RawIoBuf::new(base.add(i * chunk), chunk) })
122 }
123
124 #[inline(always)]
129 pub unsafe fn as_raw(&mut self) -> RawIoBuf {
130 unsafe { RawIoBuf::new(self.ptr.as_ptr(), self.cap).with_len(self.len) }
131 }
132
133 #[inline(always)]
138 pub unsafe fn as_raw_view(&self) -> RawIoBuf {
139 unsafe { RawIoBuf::new(self.ptr.as_ptr(), self.cap).with_len(self.len) }
140 }
141
142 #[inline(always)]
145 pub fn into_raw_parts(self) -> (NonNull<u8>, usize, usize) {
146 let me = ManuallyDrop::new(self);
147 (me.ptr, me.len, me.cap)
148 }
149
150 #[inline(always)]
155 pub unsafe fn from_raw_parts(ptr: NonNull<u8>, len: usize, cap: usize) -> Self {
156 Self { ptr, len, cap }
157 }
158
159 #[inline(always)]
160 pub fn len(&self) -> usize {
161 self.len
162 }
163
164 #[inline(always)]
165 pub fn cap(&self) -> usize {
166 self.cap
167 }
168
169 #[inline(always)]
170 pub fn is_empty(&self) -> bool {
171 self.len == 0
172 }
173
174 #[inline(always)]
175 pub fn as_ptr(&self) -> *const u8 {
176 self.ptr.as_ptr()
177 }
178
179 #[inline(always)]
180 pub fn as_mut_ptr(&mut self) -> *mut u8 {
181 self.ptr.as_ptr()
182 }
183
184 #[inline(always)]
185 pub fn clear(&mut self) {
186 self.len = 0;
187 }
188
189 #[inline(always)]
191 pub fn truncate(&mut self, len: usize) {
192 if len < self.len {
193 self.len = len;
194 }
195 }
196
197 #[inline(always)]
201 pub unsafe fn set_len(&mut self, len: usize) {
202 debug_assert!(len <= self.cap);
203 self.len = len;
204 }
205
206 pub fn try_clone(&self) -> Result<Self> {
209 let lo = layout(self.cap)?;
210 let ptr = unsafe { alloc(lo) };
211 let ptr = NonNull::new(ptr).ok_or(AllocFailed)?;
212 unsafe { copy_nonoverlapping(self.ptr.as_ptr(), ptr.as_ptr(), self.len) };
213 Ok(Self {
214 ptr,
215 len: self.len,
216 cap: self.cap,
217 })
218 }
219
220 #[inline]
222 pub fn extend(&mut self, data: &[u8]) -> Result<()> {
223 let new_len = self.len + data.len();
224 if new_len > self.cap {
225 return Err(Overflow(new_len, self.cap));
226 }
227 unsafe { copy_nonoverlapping(data.as_ptr(), self.ptr.as_ptr().add(self.len), data.len()) };
228 self.len = new_len;
229 Ok(())
230 }
231}
232
233impl Drop for AlignedBuf {
234 fn drop(&mut self) {
235 unsafe { dealloc(self.ptr.as_ptr(), layout_unchecked(self.cap)) }
236 }
237}
238
239impl Deref for AlignedBuf {
240 type Target = [u8];
241
242 #[inline]
243 fn deref(&self) -> &[u8] {
244 unsafe { from_raw_parts(self.ptr.as_ptr(), self.len) }
245 }
246}
247
248impl DerefMut for AlignedBuf {
249 #[inline]
250 fn deref_mut(&mut self) -> &mut [u8] {
251 unsafe { from_raw_parts_mut(self.ptr.as_ptr(), self.len) }
252 }
253}
254
255impl AsRef<[u8]> for AlignedBuf {
256 #[inline]
257 fn as_ref(&self) -> &[u8] {
258 self
259 }
260}
261
262impl AsMut<[u8]> for AlignedBuf {
263 #[inline]
264 fn as_mut(&mut self) -> &mut [u8] {
265 self
266 }
267}
268
269impl Clone for AlignedBuf {
270 fn clone(&self) -> Self {
271 self
272 .try_clone()
273 .unwrap_or_else(|_| handle_alloc_error(layout_unchecked(self.cap)))
274 }
275}
276
277impl Debug for AlignedBuf {
278 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
279 f.debug_struct("AlignedBuf")
280 .field("len", &self.len)
281 .field("cap", &self.cap)
282 .finish()
283 }
284}
285
286unsafe impl IoBuf for AlignedBuf {
289 #[inline(always)]
290 fn as_buf_ptr(&self) -> *const u8 {
291 self.ptr.as_ptr()
292 }
293
294 #[inline(always)]
295 fn buf_len(&self) -> usize {
296 self.len
297 }
298
299 #[inline(always)]
300 fn buf_capacity(&self) -> usize {
301 self.cap
302 }
303}
304
305unsafe impl IoBufMut for AlignedBuf {
306 #[inline(always)]
307 fn as_buf_mut_ptr(&mut self) -> *mut u8 {
308 self.ptr.as_ptr()
309 }
310}
311
312impl SetBufInit for AlignedBuf {
313 #[inline(always)]
314 unsafe fn set_buf_init(&mut self, len: usize) {
315 self.len = len;
316 }
317}
318
319#[repr(C)]
329#[derive(Clone, Copy)]
330pub struct RawIoBuf {
331 ptr: *mut u8,
332 len: usize,
333 cap: usize,
334}
335
336unsafe impl Send for RawIoBuf {}
339unsafe impl Sync for RawIoBuf {}
340
341impl RawIoBuf {
342 #[inline(always)]
346 pub const unsafe fn new(ptr: *mut u8, cap: usize) -> Self {
347 Self { ptr, len: 0, cap }
348 }
349
350 #[inline(always)]
352 pub const fn with_len(mut self, len: usize) -> Self {
353 self.len = len;
354 self
355 }
356
357 #[inline(always)]
361 pub const unsafe fn from_raw_parts(ptr: NonNull<u8>, len: usize, cap: usize) -> Self {
362 Self {
363 ptr: ptr.as_ptr(),
364 len,
365 cap,
366 }
367 }
368
369 #[inline(always)]
371 pub fn from_slice(slice: &mut [u8]) -> Self {
372 Self {
373 ptr: slice.as_mut_ptr(),
374 len: slice.len(),
375 cap: slice.len(),
376 }
377 }
378
379 #[inline]
385 pub unsafe fn slice(self, offset: usize, len: usize) -> Self {
386 debug_assert!(offset + len <= self.cap, "slice out of bounds");
387 debug_assert!(
388 (self.ptr as usize + offset) & ALIGN_MASK == 0,
389 "slice not aligned"
390 );
391 Self {
392 ptr: unsafe { self.ptr.add(offset) },
393 len: 0,
394 cap: len,
395 }
396 }
397
398 #[inline]
404 pub unsafe fn slice_data(self, offset: usize, len: usize) -> Self {
405 debug_assert!(offset + len <= self.cap, "slice out of bounds");
406 debug_assert!(
407 (self.ptr as usize + offset) & ALIGN_MASK == 0,
408 "slice not aligned"
409 );
410 Self {
411 ptr: unsafe { self.ptr.add(offset) },
412 len,
413 cap: len,
414 }
415 }
416
417 #[inline(always)]
421 pub unsafe fn slice_unchecked(self, offset: usize, len: usize) -> Self {
422 Self {
423 ptr: unsafe { self.ptr.add(offset) },
424 len: 0,
425 cap: len,
426 }
427 }
428
429 #[inline(always)]
430 pub const fn len(&self) -> usize {
431 self.len
432 }
433
434 #[inline(always)]
435 pub const fn cap(&self) -> usize {
436 self.cap
437 }
438
439 #[inline(always)]
440 pub const fn is_empty(&self) -> bool {
441 self.len == 0
442 }
443
444 #[inline(always)]
445 pub const fn as_ptr(&self) -> *const u8 {
446 self.ptr
447 }
448
449 #[inline(always)]
450 pub const fn as_mut_ptr(&self) -> *mut u8 {
451 self.ptr
452 }
453
454 #[inline(always)]
455 pub fn as_slice(&self) -> &[u8] {
456 unsafe { from_raw_parts(self.ptr, self.len) }
457 }
458
459 #[inline(always)]
460 pub fn as_mut_slice(&mut self) -> &mut [u8] {
461 unsafe { from_raw_parts_mut(self.ptr, self.len) }
462 }
463
464 #[inline(always)]
468 pub unsafe fn set_len(&mut self, len: usize) {
469 debug_assert!(len <= self.cap);
470 self.len = len;
471 }
472}
473
474impl Debug for RawIoBuf {
475 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
476 f.debug_struct("RawIoBuf")
477 .field("ptr", &self.ptr)
478 .field("len", &self.len)
479 .field("cap", &self.cap)
480 .finish()
481 }
482}
483
484unsafe impl IoBuf for RawIoBuf {
487 #[inline(always)]
488 fn as_buf_ptr(&self) -> *const u8 {
489 self.ptr
490 }
491
492 #[inline(always)]
493 fn buf_len(&self) -> usize {
494 self.len
495 }
496
497 #[inline(always)]
498 fn buf_capacity(&self) -> usize {
499 self.cap
500 }
501}
502
503unsafe impl IoBufMut for RawIoBuf {
504 #[inline(always)]
505 fn as_buf_mut_ptr(&mut self) -> *mut u8 {
506 self.ptr
507 }
508}
509
510impl SetBufInit for RawIoBuf {
511 #[inline(always)]
512 unsafe fn set_buf_init(&mut self, len: usize) {
513 self.len = len;
514 }
515}