1#![allow(unsafe_code)]
7
8use bytes::Bytes;
9use compio::buf::{IoBufMut, SetBufInit};
10use std::alloc::{alloc, dealloc, Layout};
11use std::ptr::NonNull;
12use std::sync::Arc;
13
14pub const PAGE_SIZE: usize = 64 * 1024;
17
18pub const PAGE_ALIGN: usize = 128;
20
21struct Page {
27 ptr: NonNull<u8>,
28}
29
30unsafe impl Send for Page {}
31unsafe impl Sync for Page {}
32
33impl Drop for Page {
34 fn drop(&mut self) {
35 unsafe {
36 let layout = Layout::from_size_align_unchecked(PAGE_SIZE, PAGE_ALIGN);
37 dealloc(self.ptr.as_ptr(), layout);
38 }
39 }
40}
41
42struct PageOwner {
48 page: Arc<Page>,
49}
50
51impl AsRef<[u8]> for PageOwner {
52 fn as_ref(&self) -> &[u8] {
53 unsafe { std::slice::from_raw_parts(self.page.ptr.as_ptr(), PAGE_SIZE) }
54 }
55}
56
57pub struct SlabMut {
64 page: Arc<Page>,
65 ptr: NonNull<u8>,
66 cap: usize,
67 len: usize,
68}
69
70unsafe impl Send for SlabMut {}
71unsafe impl Sync for SlabMut {}
72
73unsafe impl compio::buf::IoBuf for SlabMut {
78 #[inline]
79 fn as_buf_ptr(&self) -> *const u8 {
80 self.ptr.as_ptr()
81 }
82
83 #[inline]
84 fn buf_len(&self) -> usize {
85 self.len
86 }
87
88 #[inline]
89 fn buf_capacity(&self) -> usize {
90 self.cap
91 }
92}
93
94unsafe impl IoBufMut for SlabMut {
100 #[inline]
101 fn as_buf_mut_ptr(&mut self) -> *mut u8 {
102 self.ptr.as_ptr()
103 }
104}
105
106impl SetBufInit for SlabMut {
107 #[inline]
108 unsafe fn set_buf_init(&mut self, len: usize) {
109 debug_assert!(len <= self.cap);
110 self.len = len;
111 }
112}
113
114impl SlabMut {
115 #[must_use]
122 pub fn freeze(self) -> Bytes {
123 let base = self.page.ptr.as_ptr();
124 let offset = unsafe { self.ptr.as_ptr().offset_from(base) } as usize;
125
126 debug_assert!(offset + self.len <= PAGE_SIZE);
127
128 let owner = PageOwner { page: self.page };
129
130 let full = Bytes::from_owner(owner);
132 full.slice(offset..offset + self.len)
133 }
134}
135
136pub struct IoArena {
141 current: Option<Arc<Page>>,
142 offset: usize,
143}
144
145impl Default for IoArena {
146 fn default() -> Self {
147 Self::new()
148 }
149}
150
151impl IoArena {
152 #[must_use]
153 pub const fn new() -> Self {
154 Self {
155 current: None,
156 offset: PAGE_SIZE, }
158 }
159
160 pub fn alloc_mut(&mut self, size: usize) -> SlabMut {
171 debug_assert!(size <= PAGE_SIZE);
172
173 if self.current.is_none() || self.offset + size > PAGE_SIZE {
174 self.alloc_page();
175 }
176
177 let page = self.current.as_ref().unwrap().clone();
178
179 let ptr = unsafe { NonNull::new_unchecked(page.ptr.as_ptr().add(self.offset)) };
180
181 self.offset += size;
182
183 SlabMut {
184 page,
185 ptr,
186 cap: size,
187 len: 0,
188 }
189 }
190
191 #[inline(never)]
192 fn alloc_page(&mut self) {
193 unsafe {
194 let layout = Layout::from_size_align_unchecked(PAGE_SIZE, PAGE_ALIGN);
195 let ptr = alloc(layout);
196 if ptr.is_null() {
197 std::alloc::handle_alloc_error(layout);
198 }
199
200 self.current = Some(Arc::new(Page {
201 ptr: NonNull::new_unchecked(ptr),
202 }));
203 self.offset = 0;
204 }
205 }
206}