compio_buf/io_slice.rs
1use std::mem::MaybeUninit;
2
3#[cfg(unix)]
4mod sys {
5 use std::mem::MaybeUninit;
6
7 #[repr(transparent)]
8 pub struct Inner(libc::iovec);
9
10 impl Inner {
11 pub fn new(ptr: *mut MaybeUninit<u8>, len: usize) -> Self {
12 Self(libc::iovec {
13 iov_base: ptr as *mut libc::c_void,
14 iov_len: len,
15 })
16 }
17
18 pub fn len(&self) -> usize {
19 self.0.iov_len
20 }
21
22 pub fn as_ptr(&self) -> *mut MaybeUninit<u8> {
23 self.0.iov_base as *mut MaybeUninit<u8>
24 }
25 }
26}
27
28#[cfg(windows)]
29mod sys {
30 use std::mem::MaybeUninit;
31
32 // Copied from std
33 #[repr(C)]
34 #[allow(clippy::upper_case_acronyms)]
35 struct WSABUF {
36 pub len: u32,
37 pub buf: *mut MaybeUninit<u8>,
38 }
39
40 #[repr(transparent)]
41 pub struct Inner(WSABUF);
42
43 impl Inner {
44 pub fn new(ptr: *mut MaybeUninit<u8>, len: usize) -> Self {
45 Self(WSABUF {
46 len: len as u32,
47 buf: ptr,
48 })
49 }
50
51 pub fn len(&self) -> usize {
52 self.0.len as _
53 }
54
55 pub fn as_ptr(&self) -> *mut MaybeUninit<u8> {
56 self.0.buf
57 }
58 }
59}
60
61#[cfg(not(any(unix, windows)))]
62compile_error!("`IoSlice` only available on unix and windows");
63
64/// An unsafe, `'static`, initialized, and immutable slice of bytes to interact
65/// with system API.
66///
67/// Like [`IoSlice`] in `std`, `IoSlice` guarantees the ABI compatibility
68/// on unix and windows, but without the lifetime, makes it easier to use with
69/// compio driver at the cost of unsafe to construct. `IoSlice` should only be
70/// used with compio driver.
71///
72/// [`IoSlice`]: std::io::IoSlice
73#[repr(transparent)]
74pub struct IoSlice(sys::Inner);
75
76impl IoSlice {
77 /// Create a new `IoSlice` from a raw pointer and a length.
78 ///
79 /// # Safety
80 /// The caller must ensure that:
81 /// - the pointer is valid for the lifetime of the `IoSlice`
82 /// - the length is correct
83 /// - the content of the buffer is initialized
84 /// - the pointer is not used for mutating while the `IoSlice` is in use
85 pub unsafe fn new(ptr: *const u8, len: usize) -> Self {
86 Self(sys::Inner::new(ptr as _, len))
87 }
88
89 /// Create a new `IoSlice` from an initialized slice.
90 ///
91 /// # Safety
92 /// The caller must ensure that, during the lifetime of the `IoSlice`, the
93 /// slice is valid the and is not used for mutating.
94 pub unsafe fn from_slice(slice: &[u8]) -> Self {
95 // SAFETY:
96 // - the length is correct
97 // - the content of the buffer is initialized
98 // - the slice is not used for mutating while the `IoSlice` is in use
99 unsafe { Self::new(slice.as_ptr() as _, slice.len()) }
100 }
101
102 /// Get the pointer to the buffer.
103 pub fn as_ptr(&self) -> *const u8 {
104 self.0.as_ptr() as _
105 }
106
107 /// Get the length of the buffer.
108 pub fn len(&self) -> usize {
109 self.0.len()
110 }
111
112 /// Check if the buffer is empty.
113 pub fn is_empty(&self) -> bool {
114 self.len() == 0
115 }
116}
117
118/// An unsafe, `'static`, maybe uninitialized, and mutable slice of bytes to
119/// interact with system API.
120///
121/// Like [`IoSliceMut`] in `std`, `IoSliceMut` guarantees the ABI compatibility
122/// on unix and windows, but without the lifetime and accepts
123/// [`MaybeUninit<u8>`], makes it easier to use with compio driver at the cost
124/// of unsafe to construct. `IoSliceMut` should only be used with compio driver.
125///
126/// [`IoSliceMut`]: std::io::IoSliceMut
127#[repr(transparent)]
128pub struct IoSliceMut(sys::Inner);
129
130impl IoSliceMut {
131 /// Create a new `IoSliceMut` from a raw pointer and a length.
132 ///
133 /// # Safety
134 /// The caller must ensure that:
135 /// - the pointer is valid for the lifetime of the `IoSliceMut`
136 /// - the length is correct (the content can be uninitialized, but must be
137 /// accessible)
138 /// - the pointer is not used for anything else while the `IoSliceMut` is in
139 /// use
140 pub unsafe fn new(ptr: *mut MaybeUninit<u8>, len: usize) -> Self {
141 Self(sys::Inner::new(ptr, len))
142 }
143
144 /// Create a new `IoSliceMut` from an initialized slice.
145 ///
146 /// # Safety
147 /// The caller must ensure that, during the lifetime of the `IoSliceMut`,
148 /// the slice is valid the and is not used for anything else.
149 pub unsafe fn from_slice(slice: &mut [u8]) -> Self {
150 // SAFETY:
151 // - the length is correct
152 // - the slice is not used for anything else while the `IoSliceMut` is in use
153 unsafe { Self::new(slice.as_mut_ptr() as _, slice.len()) }
154 }
155
156 /// Create a new `IoSliceMut` from a uninitialized slice.
157 ///
158 /// # Safety
159 /// The caller must ensure that, during the lifetime of the `IoSliceMut`,
160 /// the slice is valid the and is not used for anything else.
161 pub unsafe fn from_uninit(slice: &mut [MaybeUninit<u8>]) -> Self {
162 // SAFETY:
163 // - the length is correct
164 // - the slice is not used for anything else while the `IoSliceMut` is in use
165 unsafe { Self::new(slice.as_mut_ptr(), slice.len()) }
166 }
167
168 /// Get the pointer to the buffer.
169 pub fn as_ptr(&self) -> *mut MaybeUninit<u8> {
170 self.0.as_ptr()
171 }
172
173 /// Get the length of the buffer.
174 pub fn len(&self) -> usize {
175 self.0.len()
176 }
177
178 /// Check if the buffer is empty.
179 pub fn is_empty(&self) -> bool {
180 self.len() == 0
181 }
182}
183
184/// An unsafe, `'static`, partially initialized, and mutable buffer.
185///
186/// It contains full information to describe the buffer.
187pub struct IoBuffer {
188 len: usize,
189 capacity: usize,
190 ptr: *mut MaybeUninit<u8>,
191}
192
193impl IoBuffer {
194 /// Create a new [`IoBuffer`] from a raw pointer, a length, and a capacity.
195 ///
196 /// # Safety
197 /// The caller must ensure that:
198 /// - the pointer is valid for the lifetime of the `IoBuffer`
199 /// - the length is correct (the content can be uninitialized, but must be
200 /// accessible)
201 /// - The capacity should not be smaller than the length.
202 /// - the pointer is not used for anything else while the `IoBuffer` is in
203 /// use
204 pub unsafe fn new(ptr: *mut MaybeUninit<u8>, len: usize, capacity: usize) -> Self {
205 Self { len, capacity, ptr }
206 }
207
208 /// Get the pointer to the buffer.
209 pub fn as_ptr(&self) -> *mut MaybeUninit<u8> {
210 self.ptr
211 }
212
213 /// Get the initialized length of the buffer.
214 pub fn len(&self) -> usize {
215 self.len
216 }
217
218 /// Check if the buffer is empty.
219 pub fn is_empty(&self) -> bool {
220 self.len() == 0
221 }
222
223 /// Get the full capacity of the buffer.
224 pub fn capacity(&self) -> usize {
225 self.capacity
226 }
227}
228
229impl From<IoBuffer> for IoSlice {
230 fn from(value: IoBuffer) -> Self {
231 unsafe { Self::new(value.ptr.cast(), value.len) }
232 }
233}
234
235impl From<IoBuffer> for IoSliceMut {
236 fn from(value: IoBuffer) -> Self {
237 unsafe { Self::new(value.ptr.cast(), value.capacity) }
238 }
239}