fusio_core/buf/
mod.rs

1pub mod slice;
2
3#[cfg(feature = "alloc")]
4use alloc::vec::Vec;
5use core::ops::{Bound, RangeBounds};
6
7use slice::{Buf, BufLayout, BufMut, BufMutLayout};
8
9use crate::{maybe::MaybeOwned, MaybeSend};
10
11pub trait IoBuf: Unpin + Sized + MaybeOwned + MaybeSend {
12    //! A poll-based I/O and completion-based I/O buffer compatible buffer.
13    //! The [`IoBuf`] trait is implemented by buffer types that can be used with [`crate::Read`].
14    //! Fusio has already implemented this trait for common buffer types
15    //! like `Vec<u8>`, `&[u8]`, `&mut [u8]`, `bytes::Bytes`, `bytes::BytesMut`, every buffer type
16    //! may be not be able to be used in all async runtimes, fusio provides compile-time safety to
17    //! ensure which buffer types are compatible with the async runtime.
18
19    fn as_ptr(&self) -> *const u8;
20
21    fn bytes_init(&self) -> usize;
22
23    fn as_slice(&self) -> &[u8] {
24        // SAFETY: The buffer is pinned and the bytes are initialized.
25        unsafe { core::slice::from_raw_parts(self.as_ptr(), self.bytes_init()) }
26    }
27
28    #[cfg(feature = "bytes")]
29    fn as_bytes(&self) -> bytes::Bytes {
30        bytes::Bytes::copy_from_slice(self.as_slice())
31    }
32
33    /// # Safety
34    /// The buffer must be recovered from the same type of buffer before it drops.
35    unsafe fn slice_unchecked(self, range: impl RangeBounds<usize>) -> Buf;
36
37    /// # Safety
38    /// The buffer must be recovered from the same type.
39    unsafe fn recover_from_slice(buf: Buf) -> Self;
40
41    fn calculate_bounds<R: RangeBounds<usize>>(&self, range: R) -> (usize, usize) {
42        let start = match range.start_bound() {
43            Bound::Included(&start) => start,
44            Bound::Excluded(&start) => start + 1,
45            Bound::Unbounded => 0,
46        };
47        let end = match range.end_bound() {
48            Bound::Included(&end) => end + 1,
49            Bound::Excluded(&end) => end,
50            Bound::Unbounded => self.bytes_init(),
51        };
52        (start, end)
53    }
54}
55
56pub trait IoBufMut: IoBuf {
57    //! Mutable version of [`IoBuf`] which is used with [`crate::Write`].
58
59    fn as_mut_ptr(&mut self) -> *mut u8;
60
61    fn as_slice_mut(&mut self) -> &mut [u8] {
62        // SAFETY: The buffer is pinned and the bytes are initialized.
63        unsafe { core::slice::from_raw_parts_mut(self.as_mut_ptr(), self.bytes_init()) }
64    }
65
66    /// # Safety
67    /// The buffer must be recovered from the same type of buffer before it drops.
68    unsafe fn slice_mut_unchecked(self, range: impl RangeBounds<usize>) -> BufMut;
69
70    /// # Safety
71    /// The buffer must be recovered from the same type.
72    unsafe fn recover_from_slice_mut(buf: BufMut) -> Self;
73}
74
75#[cfg(feature = "alloc")]
76impl IoBuf for Vec<u8> {
77    fn as_ptr(&self) -> *const u8 {
78        self.as_ptr()
79    }
80
81    fn bytes_init(&self) -> usize {
82        self.len()
83    }
84
85    unsafe fn slice_unchecked(self, range: impl RangeBounds<usize>) -> Buf {
86        let (start, end) = self.calculate_bounds(range);
87        Buf {
88            layout: BufLayout::Vec(self),
89            start,
90            end,
91        }
92    }
93
94    unsafe fn recover_from_slice(buf: Buf) -> Self {
95        match buf.layout {
96            BufLayout::Vec(vec) => vec,
97            _ => unreachable!(),
98        }
99    }
100}
101
102#[cfg(feature = "alloc")]
103impl IoBufMut for Vec<u8> {
104    fn as_mut_ptr(&mut self) -> *mut u8 {
105        Vec::as_mut_ptr(self)
106    }
107
108    unsafe fn slice_mut_unchecked(self, range: impl RangeBounds<usize>) -> BufMut {
109        let (start, end) = self.calculate_bounds(range);
110        BufMut {
111            layout: BufMutLayout::Vec(self),
112            start,
113            end,
114        }
115    }
116
117    unsafe fn recover_from_slice_mut(buf: BufMut) -> Self {
118        match buf.layout {
119            BufMutLayout::Vec(vec) => vec,
120            _ => unreachable!(),
121        }
122    }
123}
124
125#[cfg(not(feature = "completion-based"))]
126impl IoBuf for &[u8] {
127    fn as_ptr(&self) -> *const u8 {
128        (*self).as_ptr()
129    }
130
131    fn bytes_init(&self) -> usize {
132        self.len()
133    }
134
135    unsafe fn slice_unchecked(self, range: impl RangeBounds<usize>) -> Buf {
136        let (start, end) = self.calculate_bounds(range);
137        Buf {
138            layout: BufLayout::Slice {
139                ptr: self.as_ptr() as *mut u8,
140                len: self.len(),
141            },
142            start,
143            end,
144        }
145    }
146
147    unsafe fn recover_from_slice(buf: Buf) -> Self {
148        match buf.layout {
149            BufLayout::Slice { ptr, len } => core::slice::from_raw_parts(ptr, len),
150            _ => unreachable!(),
151        }
152    }
153}
154
155#[cfg(not(feature = "completion-based"))]
156impl IoBuf for &mut [u8] {
157    fn as_ptr(&self) -> *const u8 {
158        <[u8]>::as_ptr(self)
159    }
160
161    fn bytes_init(&self) -> usize {
162        self.len()
163    }
164
165    unsafe fn slice_unchecked(self, range: impl RangeBounds<usize>) -> Buf {
166        let (start, end) = self.calculate_bounds(range);
167        Buf {
168            layout: BufLayout::Slice {
169                ptr: self.as_ptr() as *mut u8,
170                len: self.len(),
171            },
172            start,
173            end,
174        }
175    }
176
177    unsafe fn recover_from_slice(buf: Buf) -> Self {
178        match buf.layout {
179            BufLayout::Slice { ptr, len } => core::slice::from_raw_parts_mut(ptr as *mut u8, len),
180            _ => unreachable!(),
181        }
182    }
183}
184
185#[cfg(not(feature = "completion-based"))]
186impl IoBufMut for &mut [u8] {
187    fn as_mut_ptr(&mut self) -> *mut u8 {
188        <[u8]>::as_mut_ptr(self)
189    }
190
191    unsafe fn slice_mut_unchecked(self, range: impl RangeBounds<usize>) -> BufMut {
192        let (start, end) = self.calculate_bounds(range);
193        BufMut {
194            layout: BufMutLayout::Slice {
195                ptr: self.as_mut_ptr(),
196                len: self.len(),
197            },
198            start,
199            end,
200        }
201    }
202
203    unsafe fn recover_from_slice_mut(buf: BufMut) -> Self {
204        match buf.layout {
205            BufMutLayout::Slice { ptr, len } => core::slice::from_raw_parts_mut(ptr, len),
206            _ => unreachable!(),
207        }
208    }
209}
210
211#[cfg(feature = "completion-based")]
212impl IoBuf for &'static [u8] {
213    fn as_ptr(&self) -> *const u8 {
214        (*self).as_ptr()
215    }
216
217    fn bytes_init(&self) -> usize {
218        self.len()
219    }
220
221    #[cfg(feature = "bytes")]
222    fn as_bytes(&self) -> bytes::Bytes {
223        bytes::Bytes::from_static(self)
224    }
225
226    unsafe fn slice_unchecked(self, range: impl RangeBounds<usize>) -> Buf {
227        let (start, end) = self.calculate_bounds(range);
228        Buf {
229            layout: BufLayout::Slice {
230                ptr: self.as_ptr() as *mut u8,
231                len: self.len(),
232            },
233            start,
234            end,
235        }
236    }
237
238    unsafe fn recover_from_slice(buf: Buf) -> Self {
239        match buf.layout {
240            BufLayout::Slice { ptr, len } => core::slice::from_raw_parts(ptr, len),
241            _ => unreachable!(),
242        }
243    }
244}
245
246#[cfg(feature = "bytes")]
247impl IoBuf for bytes::Bytes {
248    fn as_ptr(&self) -> *const u8 {
249        <[u8]>::as_ptr(self)
250    }
251
252    fn bytes_init(&self) -> usize {
253        self.len()
254    }
255    fn as_bytes(&self) -> bytes::Bytes {
256        self.clone()
257    }
258
259    unsafe fn slice_unchecked(self, range: impl RangeBounds<usize>) -> Buf {
260        let start = match range.start_bound() {
261            Bound::Included(&start) => start,
262            Bound::Excluded(&start) => start + 1,
263            Bound::Unbounded => 0,
264        };
265        let end = match range.end_bound() {
266            Bound::Included(&end) => end + 1,
267            Bound::Excluded(&end) => end,
268            Bound::Unbounded => self.len(),
269        };
270        Buf {
271            layout: BufLayout::Bytes(self),
272            start,
273            end,
274        }
275    }
276
277    unsafe fn recover_from_slice(buf: Buf) -> Self {
278        match buf.layout {
279            BufLayout::Bytes(bytes) => bytes,
280            _ => unreachable!(),
281        }
282    }
283}
284
285#[cfg(feature = "bytes")]
286impl IoBuf for bytes::BytesMut {
287    fn as_ptr(&self) -> *const u8 {
288        <[u8]>::as_ptr(self)
289    }
290
291    fn bytes_init(&self) -> usize {
292        self.len()
293    }
294
295    fn as_bytes(&self) -> bytes::Bytes {
296        self.clone().freeze()
297    }
298
299    unsafe fn slice_unchecked(self, range: impl RangeBounds<usize>) -> Buf {
300        let start = match range.start_bound() {
301            Bound::Included(&start) => start,
302            Bound::Excluded(&start) => start + 1,
303            Bound::Unbounded => 0,
304        };
305        let end = match range.end_bound() {
306            Bound::Included(&end) => end + 1,
307            Bound::Excluded(&end) => end,
308            Bound::Unbounded => self.len(),
309        };
310        Buf {
311            layout: BufLayout::BytesMut(self),
312            start,
313            end,
314        }
315    }
316
317    unsafe fn recover_from_slice(buf: Buf) -> Self {
318        match buf.layout {
319            BufLayout::BytesMut(bytes) => bytes,
320            _ => unreachable!(),
321        }
322    }
323}
324
325#[cfg(feature = "bytes")]
326impl IoBufMut for bytes::BytesMut {
327    fn as_mut_ptr(&mut self) -> *mut u8 {
328        <[u8]>::as_mut_ptr(self)
329    }
330
331    unsafe fn slice_mut_unchecked(self, range: impl RangeBounds<usize>) -> BufMut {
332        let start = match range.start_bound() {
333            Bound::Included(&start) => start,
334            Bound::Excluded(&start) => start + 1,
335            Bound::Unbounded => 0,
336        };
337        let end = match range.end_bound() {
338            Bound::Included(&end) => end + 1,
339            Bound::Excluded(&end) => end,
340            Bound::Unbounded => self.len(),
341        };
342        BufMut {
343            layout: BufMutLayout::BytesMut(self),
344            start,
345            end,
346        }
347    }
348
349    unsafe fn recover_from_slice_mut(buf: BufMut) -> Self {
350        match buf.layout {
351            BufMutLayout::BytesMut(bytes) => bytes,
352            _ => unreachable!(),
353        }
354    }
355}