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}