compio_buf/
io_slice.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
use std::mem::MaybeUninit;

#[cfg(unix)]
mod sys {
    use std::mem::MaybeUninit;

    #[repr(transparent)]
    pub struct Inner(libc::iovec);

    impl Inner {
        pub fn new(ptr: *mut MaybeUninit<u8>, len: usize) -> Self {
            Self(libc::iovec {
                iov_base: ptr as *mut libc::c_void,
                iov_len: len,
            })
        }

        pub fn len(&self) -> usize {
            self.0.iov_len
        }

        pub fn as_ptr(&self) -> *mut MaybeUninit<u8> {
            self.0.iov_base as *mut MaybeUninit<u8>
        }
    }
}

#[cfg(windows)]
mod sys {
    use std::mem::MaybeUninit;

    // Copied from std
    #[repr(C)]
    #[allow(clippy::upper_case_acronyms)]
    struct WSABUF {
        pub len: u32,
        pub buf: *mut MaybeUninit<u8>,
    }

    #[repr(transparent)]
    pub struct Inner(WSABUF);

    impl Inner {
        pub fn new(ptr: *mut MaybeUninit<u8>, len: usize) -> Self {
            Self(WSABUF {
                len: len as u32,
                buf: ptr,
            })
        }

        pub fn len(&self) -> usize {
            self.0.len as _
        }

        pub fn as_ptr(&self) -> *mut MaybeUninit<u8> {
            self.0.buf
        }
    }
}

#[cfg(not(any(unix, windows)))]
compile_error!("`IoSlice` only available on unix and windows");

/// An unsafe, `'static`, initialized, and immutable slice of bytes to interact
/// with system API.
///
/// Like [`IoSlice`] in `std`, `IoSlice` guarantees the ABI compatibility
/// on unix and windows, but without the lifetime, makes it easier to use with
/// compio driver at the cost of unsafe to construct. `IoSlice` should only be
/// used with compio driver.
///
/// [`IoSlice`]: std::io::IoSlice
#[repr(transparent)]
pub struct IoSlice(sys::Inner);

impl IoSlice {
    /// Create a new `IoSlice` from a raw pointer and a length.
    ///
    /// # Safety
    /// The caller must ensure that:
    /// - the pointer is valid for the lifetime of the `IoSlice`
    /// - the length is correct
    /// - the content of the buffer is initialized
    /// - the pointer is not used for mutating while the `IoSlice` is in use
    pub unsafe fn new(ptr: *const u8, len: usize) -> Self {
        Self(sys::Inner::new(ptr as _, len))
    }

    /// Create a new `IoSlice` from an initialized slice.
    ///
    /// # Safety
    /// The caller must ensure that, during the lifetime of the `IoSlice`, the
    /// slice is valid the and is not used for mutating.
    pub unsafe fn from_slice(slice: &[u8]) -> Self {
        Self::new(slice.as_ptr() as _, slice.len())
    }

    /// Get the pointer to the buffer.
    pub fn as_ptr(&self) -> *const u8 {
        self.0.as_ptr() as _
    }

    /// Get the length of the buffer.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Check if the buffer is empty.
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

/// An unsafe, `'static`, maybe uninitialized, and mutable slice of bytes to
/// interact with system API.
///
/// Like [`IoSliceMut`] in `std`, `IoSliceMut` guarantees the ABI compatibility
/// on unix and windows, but without the lifetime and accepts
/// [`MaybeUninit<u8>`], makes it easier to use with compio driver at the cost
/// of unsafe to construct. `IoSliceMut` should only be used with compio driver.
///
/// [`IoSliceMut`]: std::io::IoSliceMut
#[repr(transparent)]
pub struct IoSliceMut(sys::Inner);

impl IoSliceMut {
    /// Create a new `IoSliceMut` from a raw pointer and a length.
    ///
    /// # Safety
    /// The caller must ensure that:
    /// - the pointer is valid for the lifetime of the `IoSliceMut`
    /// - the length is correct (the content can be uninitialized, but must be
    ///   accessible)
    /// - the pointer is not used for anything else while the `IoSliceMut` is in
    ///   use
    pub unsafe fn new(ptr: *mut MaybeUninit<u8>, len: usize) -> Self {
        Self(sys::Inner::new(ptr, len))
    }

    /// Create a new `IoSliceMut` from an initialized slice.
    ///
    /// # Safety
    /// The caller must ensure that, during the lifetime of the `IoSliceMut`,
    /// the slice is valid the and is not used for anything else.
    pub unsafe fn from_slice(slice: &mut [u8]) -> Self {
        Self::new(slice.as_mut_ptr() as _, slice.len())
    }

    /// Create a new `IoSliceMut` from a uninitialized slice.
    ///
    /// # Safety
    /// The caller must ensure that, during the lifetime of the `IoSliceMut`,
    /// the slice is valid the and is not used for anything else.
    pub unsafe fn from_uninit(slice: &mut [MaybeUninit<u8>]) -> Self {
        Self::new(slice.as_mut_ptr(), slice.len())
    }

    /// Get the pointer to the buffer.
    pub fn as_ptr(&self) -> *mut MaybeUninit<u8> {
        self.0.as_ptr()
    }

    /// Get the length of the buffer.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Check if the buffer is empty.
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
}