monoio/buf/
io_buf.rs

1use std::{ops, rc::Rc, sync::Arc};
2
3use super::Slice;
4use crate::buf::slice::SliceMut;
5
6/// An `io_uring` compatible buffer.
7///
8/// The `IoBuf` trait is implemented by buffer types that can be passed to
9/// io_uring operations. Users will not need to use this trait directly, except
10/// for the [`slice`] method.
11///
12/// # Slicing
13///
14/// Because buffers are passed by ownership to the runtime, Rust's slice API
15/// (`&buf[..]`) cannot be used. Instead, `monoio` provides an owned slice
16/// API: [`slice()`]. The method takes ownership of the buffer and returns a
17/// `Slice<Self>` type that tracks the requested offset.
18///
19/// [`slice()`]: IoBuf::slice
20/// # Safety
21/// impl it safely
22pub unsafe trait IoBuf: Unpin + 'static {
23    /// Returns a raw pointer to the vector's buffer.
24    ///
25    /// This method is to be used by the `monoio` runtime and it is not
26    /// expected for users to call it directly.
27    ///
28    /// `monoio` Runtime will `Box::pin` the buffer. Runtime makes sure
29    /// the buffer will not be moved, and the implement must ensure
30    /// `as_ptr` returns the same valid address.
31    /// Kernel will read `bytes_init`-length data from the pointer.
32    fn read_ptr(&self) -> *const u8;
33
34    /// Number of initialized bytes.
35    ///
36    /// This method is to be used by the `monoio` runtime and it is not
37    /// expected for users to call it directly.
38    ///
39    /// For `Vec`, this is identical to `len()`.
40    fn bytes_init(&self) -> usize;
41
42    /// Returns a slice of the buffer.
43    #[inline]
44    fn as_slice(&self) -> &[u8] {
45        unsafe { core::slice::from_raw_parts(self.read_ptr(), self.bytes_init()) }
46    }
47
48    /// Returns a view of the buffer with the specified range.
49    #[inline]
50    fn slice(self, range: impl ops::RangeBounds<usize>) -> Slice<Self>
51    where
52        Self: Sized,
53    {
54        let (begin, end) = parse_range(range, self.bytes_init());
55        Slice::new(self, begin, end)
56    }
57
58    /// Returns a view of the buffer with the specified range without boundary
59    /// checking.
60    ///
61    /// # Safety
62    /// Range must be within the bounds of the buffer.
63    #[inline]
64    unsafe fn slice_unchecked(self, range: impl ops::RangeBounds<usize>) -> Slice<Self>
65    where
66        Self: Sized,
67    {
68        let (begin, end) = parse_range(range, self.bytes_init());
69        Slice::new_unchecked(self, begin, end)
70    }
71}
72
73unsafe impl IoBuf for Vec<u8> {
74    #[inline]
75    fn read_ptr(&self) -> *const u8 {
76        self.as_ptr()
77    }
78
79    #[inline]
80    fn bytes_init(&self) -> usize {
81        self.len()
82    }
83}
84
85unsafe impl IoBuf for Box<[u8]> {
86    #[inline]
87    fn read_ptr(&self) -> *const u8 {
88        self.as_ptr()
89    }
90
91    #[inline]
92    fn bytes_init(&self) -> usize {
93        self.len()
94    }
95}
96
97unsafe impl IoBuf for &'static [u8] {
98    #[inline]
99    fn read_ptr(&self) -> *const u8 {
100        self.as_ptr()
101    }
102
103    #[inline]
104    fn bytes_init(&self) -> usize {
105        <[u8]>::len(self)
106    }
107}
108
109unsafe impl<const N: usize> IoBuf for Box<[u8; N]> {
110    #[inline]
111    fn read_ptr(&self) -> *const u8 {
112        self.as_ptr()
113    }
114
115    #[inline]
116    fn bytes_init(&self) -> usize {
117        self.len()
118    }
119}
120
121unsafe impl<const N: usize> IoBuf for &'static [u8; N] {
122    #[inline]
123    fn read_ptr(&self) -> *const u8 {
124        self.as_ptr()
125    }
126
127    #[inline]
128    fn bytes_init(&self) -> usize {
129        self.len()
130    }
131}
132
133unsafe impl<const N: usize> IoBuf for &'static mut [u8; N] {
134    #[inline]
135    fn read_ptr(&self) -> *const u8 {
136        self.as_ptr()
137    }
138
139    #[inline]
140    fn bytes_init(&self) -> usize {
141        self.len()
142    }
143}
144
145unsafe impl IoBuf for &'static str {
146    #[inline]
147    fn read_ptr(&self) -> *const u8 {
148        self.as_ptr()
149    }
150
151    #[inline]
152    fn bytes_init(&self) -> usize {
153        <str>::len(self)
154    }
155}
156
157#[cfg(feature = "bytes")]
158unsafe impl IoBuf for bytes::Bytes {
159    #[inline]
160    fn read_ptr(&self) -> *const u8 {
161        self.as_ptr()
162    }
163
164    #[inline]
165    fn bytes_init(&self) -> usize {
166        self.len()
167    }
168}
169
170#[cfg(feature = "bytes")]
171unsafe impl IoBuf for bytes::BytesMut {
172    #[inline]
173    fn read_ptr(&self) -> *const u8 {
174        self.as_ptr()
175    }
176
177    #[inline]
178    fn bytes_init(&self) -> usize {
179        self.len()
180    }
181}
182
183unsafe impl<T> IoBuf for Rc<T>
184where
185    T: IoBuf,
186{
187    #[inline]
188    fn read_ptr(&self) -> *const u8 {
189        <T as IoBuf>::read_ptr(self)
190    }
191
192    #[inline]
193    fn bytes_init(&self) -> usize {
194        <T as IoBuf>::bytes_init(self)
195    }
196}
197
198unsafe impl<T> IoBuf for Arc<T>
199where
200    T: IoBuf,
201{
202    #[inline]
203    fn read_ptr(&self) -> *const u8 {
204        <T as IoBuf>::read_ptr(self)
205    }
206
207    #[inline]
208    fn bytes_init(&self) -> usize {
209        <T as IoBuf>::bytes_init(self)
210    }
211}
212
213unsafe impl<T> IoBuf for std::mem::ManuallyDrop<T>
214where
215    T: IoBuf,
216{
217    fn read_ptr(&self) -> *const u8 {
218        <T as IoBuf>::read_ptr(self)
219    }
220
221    fn bytes_init(&self) -> usize {
222        <T as IoBuf>::bytes_init(self)
223    }
224}
225
226/// A mutable `io_uring` compatible buffer.
227///
228/// The `IoBufMut` trait is implemented by buffer types that can be passed to
229/// io_uring operations. Users will not need to use this trait directly.
230///
231/// # Safety
232/// See the safety note of the methods.
233pub unsafe trait IoBufMut: Unpin + 'static {
234    /// Returns a raw mutable pointer to the vector's buffer.
235    ///
236    /// `monoio` Runtime will `Box::pin` the buffer. Runtime makes sure
237    /// the buffer will not be moved, and the implement must ensure
238    /// `as_ptr` returns the same valid address.
239    /// Kernel will write `bytes_init`-length data to the pointer.
240    fn write_ptr(&mut self) -> *mut u8;
241
242    /// Total size of the buffer, including uninitialized memory, if any.
243    ///
244    /// This method is to be used by the `monoio` runtime and it is not
245    /// expected for users to call it directly.
246    ///
247    /// For `Vec`, this is identical to `capacity()`.
248    fn bytes_total(&mut self) -> usize;
249
250    /// Updates the number of initialized bytes.
251    ///
252    /// The specified `pos` becomes the new value returned by
253    /// `IoBuf::bytes_init`.
254    ///
255    /// # Safety
256    ///
257    /// The caller must ensure that all bytes starting at `stable_mut_ptr()` up
258    /// to `pos` are initialized and owned by the buffer.
259    unsafe fn set_init(&mut self, pos: usize);
260
261    /// Returns a view of the buffer with the specified range.
262    ///
263    /// This method is similar to Rust's slicing (`&buf[..]`), but takes
264    /// ownership of the buffer.
265    ///
266    /// # Examples
267    ///
268    /// ```
269    /// use monoio::buf::{IoBuf, IoBufMut};
270    ///
271    /// let buf = b"hello world".to_vec();
272    /// buf.slice(5..10);
273    /// ```
274    #[inline]
275    fn slice_mut(mut self, range: impl ops::RangeBounds<usize>) -> SliceMut<Self>
276    where
277        Self: Sized,
278        Self: IoBuf,
279    {
280        let (begin, end) = parse_range(range, self.bytes_total());
281        SliceMut::new(self, begin, end)
282    }
283
284    /// Returns a view of the buffer with the specified range.
285    ///
286    /// # Safety
287    /// Begin must within the initialized bytes, end must be within the
288    /// capacity.
289    #[inline]
290    unsafe fn slice_mut_unchecked(mut self, range: impl ops::RangeBounds<usize>) -> SliceMut<Self>
291    where
292        Self: Sized,
293    {
294        let (begin, end) = parse_range(range, self.bytes_total());
295        SliceMut::new_unchecked(self, begin, end)
296    }
297}
298
299unsafe impl IoBufMut for Vec<u8> {
300    #[inline]
301    fn write_ptr(&mut self) -> *mut u8 {
302        self.as_mut_ptr()
303    }
304
305    #[inline]
306    fn bytes_total(&mut self) -> usize {
307        self.capacity()
308    }
309
310    #[inline]
311    unsafe fn set_init(&mut self, init_len: usize) {
312        self.set_len(init_len);
313    }
314}
315
316unsafe impl IoBufMut for Box<[u8]> {
317    #[inline]
318    fn write_ptr(&mut self) -> *mut u8 {
319        self.as_mut_ptr()
320    }
321
322    #[inline]
323    fn bytes_total(&mut self) -> usize {
324        self.len()
325    }
326
327    #[inline]
328    unsafe fn set_init(&mut self, _: usize) {}
329}
330
331unsafe impl<const N: usize> IoBufMut for Box<[u8; N]> {
332    #[inline]
333    fn write_ptr(&mut self) -> *mut u8 {
334        self.as_mut_ptr()
335    }
336
337    #[inline]
338    fn bytes_total(&mut self) -> usize {
339        self.len()
340    }
341
342    #[inline]
343    unsafe fn set_init(&mut self, _: usize) {}
344}
345
346unsafe impl<const N: usize> IoBufMut for &'static mut [u8; N] {
347    #[inline]
348    fn write_ptr(&mut self) -> *mut u8 {
349        self.as_mut_ptr()
350    }
351
352    #[inline]
353    fn bytes_total(&mut self) -> usize {
354        self.len()
355    }
356
357    #[inline]
358    unsafe fn set_init(&mut self, _: usize) {}
359}
360
361#[cfg(feature = "bytes")]
362unsafe impl IoBufMut for bytes::BytesMut {
363    #[inline]
364    fn write_ptr(&mut self) -> *mut u8 {
365        self.as_mut_ptr()
366    }
367
368    #[inline]
369    fn bytes_total(&mut self) -> usize {
370        self.capacity()
371    }
372
373    #[inline]
374    unsafe fn set_init(&mut self, init_len: usize) {
375        if self.len() < init_len {
376            self.set_len(init_len);
377        }
378    }
379}
380
381unsafe impl<T> IoBufMut for std::mem::ManuallyDrop<T>
382where
383    T: IoBufMut,
384{
385    fn write_ptr(&mut self) -> *mut u8 {
386        <T as IoBufMut>::write_ptr(self)
387    }
388
389    fn bytes_total(&mut self) -> usize {
390        <T as IoBufMut>::bytes_total(self)
391    }
392
393    unsafe fn set_init(&mut self, pos: usize) {
394        <T as IoBufMut>::set_init(self, pos)
395    }
396}
397
398fn parse_range(range: impl ops::RangeBounds<usize>, end: usize) -> (usize, usize) {
399    use core::ops::Bound;
400
401    let begin = match range.start_bound() {
402        Bound::Included(&n) => n,
403        Bound::Excluded(&n) => n + 1,
404        Bound::Unbounded => 0,
405    };
406
407    let end = match range.end_bound() {
408        Bound::Included(&n) => n.checked_add(1).expect("out of range"),
409        Bound::Excluded(&n) => n,
410        Bound::Unbounded => end,
411    };
412    (begin, end)
413}
414
415#[cfg(test)]
416mod tests {
417    use std::mem::ManuallyDrop;
418
419    use super::*;
420
421    #[test]
422    fn io_buf_vec() {
423        let mut buf = Vec::with_capacity(10);
424        buf.extend_from_slice(b"0123");
425        let ptr = buf.as_mut_ptr();
426
427        assert_eq!(buf.read_ptr(), ptr);
428        assert_eq!(buf.bytes_init(), 4);
429
430        assert_eq!(buf.write_ptr(), ptr);
431        assert_eq!(buf.bytes_total(), 10);
432
433        unsafe { buf.set_init(8) };
434        assert_eq!(buf.bytes_init(), 8);
435        assert_eq!(buf.len(), 8);
436    }
437
438    #[test]
439    fn io_buf_str() {
440        let s = "hello world";
441        let ptr = s.as_ptr();
442
443        assert_eq!(s.read_ptr(), ptr);
444        assert_eq!(s.bytes_init(), 11);
445    }
446
447    #[test]
448    fn io_buf_n() {
449        let mut buf = Box::new([1, 2, 3, 4, 5]);
450        let ptr = buf.as_mut_ptr();
451
452        assert_eq!(buf.read_ptr(), ptr);
453        assert_eq!(buf.bytes_init(), 5);
454        assert_eq!(buf.write_ptr(), ptr);
455        assert_eq!(buf.bytes_total(), 5);
456    }
457
458    #[test]
459    fn io_buf_n_boxed() {
460        let mut buf = Box::new([1, 2, 3, 4, 5]);
461        let ptr = buf.as_mut_ptr();
462
463        assert_eq!(buf.read_ptr(), ptr);
464        assert_eq!(buf.bytes_init(), 5);
465        assert_eq!(buf.write_ptr(), ptr);
466        assert_eq!(buf.bytes_total(), 5);
467    }
468
469    #[test]
470    fn io_buf_n_static() {
471        let buf = &*Box::leak(Box::new([1, 2, 3, 4, 5]));
472        let ptr = buf.as_ptr();
473
474        assert_eq!(buf.read_ptr(), ptr);
475        assert_eq!(buf.bytes_init(), 5);
476    }
477
478    #[test]
479    fn io_buf_n_mut_static() {
480        let mut buf = Box::leak(Box::new([1, 2, 3, 4, 5]));
481        let ptr = buf.as_mut_ptr();
482
483        assert_eq!(buf.read_ptr(), ptr);
484        assert_eq!(buf.bytes_init(), 5);
485        assert_eq!(buf.write_ptr(), ptr);
486        assert_eq!(buf.bytes_total(), 5);
487    }
488
489    #[test]
490    fn io_buf_rc_str() {
491        let s = Rc::new("hello world");
492        let ptr = s.as_ptr();
493
494        assert_eq!(s.read_ptr(), ptr);
495        assert_eq!(s.bytes_init(), 11);
496    }
497
498    #[test]
499    fn io_buf_arc_str() {
500        let s = Arc::new("hello world");
501        let ptr = s.as_ptr();
502
503        assert_eq!(s.read_ptr(), ptr);
504        assert_eq!(s.bytes_init(), 11);
505    }
506
507    #[test]
508    fn io_buf_slice_ref() {
509        let s: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
510        let ptr = s.as_ptr();
511
512        assert_eq!(s.read_ptr(), ptr);
513        assert_eq!(s.bytes_init(), 10);
514    }
515
516    #[test]
517    fn io_buf_slice() {
518        let mut buf = Vec::with_capacity(10);
519        buf.extend_from_slice(b"0123");
520        let ptr = buf.as_mut_ptr();
521
522        let slice = buf.slice(1..3);
523        assert_eq!((slice.begin(), slice.end()), (1, 3));
524        assert_eq!(slice.read_ptr(), unsafe { ptr.add(1) });
525        assert_eq!(slice.bytes_init(), 2);
526        let buf = slice.into_inner();
527
528        let mut slice = buf.slice_mut(1..8);
529        assert_eq!((slice.begin(), slice.end()), (1, 8));
530        assert_eq!(slice.write_ptr(), unsafe { ptr.add(1) });
531        assert_eq!(slice.bytes_total(), 7);
532        unsafe { slice.set_init(5) };
533        assert_eq!(slice.bytes_init(), 5);
534        assert_eq!(slice.into_inner().len(), 6);
535    }
536
537    #[test]
538    fn io_buf_arc_slice() {
539        let mut buf = Vec::with_capacity(10);
540        buf.extend_from_slice(b"0123");
541        let buf = Arc::new(buf);
542        let ptr = buf.as_ptr();
543
544        let slice = buf.slice(1..3);
545        assert_eq!((slice.begin(), slice.end()), (1, 3));
546        assert_eq!(slice.read_ptr(), unsafe { ptr.add(1) });
547        assert_eq!(slice.bytes_init(), 2);
548        let buf = Arc::into_inner(slice.into_inner()).unwrap();
549
550        let mut slice = buf.slice_mut(1..8);
551        assert_eq!((slice.begin(), slice.end()), (1, 8));
552        assert_eq!(slice.bytes_total(), 7);
553        unsafe { slice.set_init(5) };
554        assert_eq!(slice.bytes_init(), 5);
555        assert_eq!(slice.into_inner().len(), 6);
556    }
557
558    #[test]
559    fn io_buf_manually_drop() {
560        let mut buf = Vec::with_capacity(10);
561        buf.extend_from_slice(b"0123");
562        let mut buf = ManuallyDrop::new(buf);
563        let ptr = buf.as_ptr();
564
565        assert_eq!(buf.write_ptr(), ptr as _);
566        assert_eq!(buf.read_ptr(), ptr);
567        assert_eq!(buf.bytes_init(), 4);
568        unsafe { buf.set_init(3) };
569        assert_eq!(buf.bytes_init(), 3);
570        assert_eq!(buf.bytes_total(), 10);
571
572        let slice = buf.slice(1..3);
573        assert_eq!((slice.begin(), slice.end()), (1, 3));
574        assert_eq!(slice.read_ptr(), unsafe { ptr.add(1) });
575        assert_eq!(slice.bytes_init(), 2);
576        let buf = ManuallyDrop::into_inner(slice.into_inner());
577
578        let mut slice = buf.slice_mut(1..8);
579        assert_eq!((slice.begin(), slice.end()), (1, 8));
580        assert_eq!(slice.bytes_total(), 7);
581        unsafe { slice.set_init(5) };
582        assert_eq!(slice.bytes_init(), 5);
583        assert_eq!(slice.into_inner().len(), 6);
584    }
585}