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        Self::new(slice.as_ptr() as _, slice.len())
96    }
97
98    /// Get the pointer to the buffer.
99    pub fn as_ptr(&self) -> *const u8 {
100        self.0.as_ptr() as _
101    }
102
103    /// Get the length of the buffer.
104    pub fn len(&self) -> usize {
105        self.0.len()
106    }
107
108    /// Check if the buffer is empty.
109    pub fn is_empty(&self) -> bool {
110        self.len() == 0
111    }
112}
113
114/// An unsafe, `'static`, maybe uninitialized, and mutable slice of bytes to
115/// interact with system API.
116///
117/// Like [`IoSliceMut`] in `std`, `IoSliceMut` guarantees the ABI compatibility
118/// on unix and windows, but without the lifetime and accepts
119/// [`MaybeUninit<u8>`], makes it easier to use with compio driver at the cost
120/// of unsafe to construct. `IoSliceMut` should only be used with compio driver.
121///
122/// [`IoSliceMut`]: std::io::IoSliceMut
123#[repr(transparent)]
124pub struct IoSliceMut(sys::Inner);
125
126impl IoSliceMut {
127    /// Create a new `IoSliceMut` from a raw pointer and a length.
128    ///
129    /// # Safety
130    /// The caller must ensure that:
131    /// - the pointer is valid for the lifetime of the `IoSliceMut`
132    /// - the length is correct (the content can be uninitialized, but must be
133    ///   accessible)
134    /// - the pointer is not used for anything else while the `IoSliceMut` is in
135    ///   use
136    pub unsafe fn new(ptr: *mut MaybeUninit<u8>, len: usize) -> Self {
137        Self(sys::Inner::new(ptr, len))
138    }
139
140    /// Create a new `IoSliceMut` from an initialized slice.
141    ///
142    /// # Safety
143    /// The caller must ensure that, during the lifetime of the `IoSliceMut`,
144    /// the slice is valid the and is not used for anything else.
145    pub unsafe fn from_slice(slice: &mut [u8]) -> Self {
146        Self::new(slice.as_mut_ptr() as _, slice.len())
147    }
148
149    /// Create a new `IoSliceMut` from a uninitialized slice.
150    ///
151    /// # Safety
152    /// The caller must ensure that, during the lifetime of the `IoSliceMut`,
153    /// the slice is valid the and is not used for anything else.
154    pub unsafe fn from_uninit(slice: &mut [MaybeUninit<u8>]) -> Self {
155        Self::new(slice.as_mut_ptr(), slice.len())
156    }
157
158    /// Get the pointer to the buffer.
159    pub fn as_ptr(&self) -> *mut MaybeUninit<u8> {
160        self.0.as_ptr()
161    }
162
163    /// Get the length of the buffer.
164    pub fn len(&self) -> usize {
165        self.0.len()
166    }
167
168    /// Check if the buffer is empty.
169    pub fn is_empty(&self) -> bool {
170        self.len() == 0
171    }
172}