fluke_maybe_uring/buf/
io_buf.rs

1use crate::buf::Slice;
2
3use std::ops;
4
5/// An `io-uring` compatible buffer.
6///
7/// The `IoBuf` trait is implemented by buffer types that can be passed to
8/// io-uring operations. Users will not need to use this trait directly, except
9/// for the [`slice`] method.
10///
11/// # Slicing
12///
13/// Because buffers are passed by ownership to the runtime, Rust's slice API
14/// (`&buf[..]`) cannot be used. Instead, `tokio-uring` provides an owned slice
15/// API: [`slice()`]. The method takes ownership fo the buffer and returns a
16/// `Slice<Self>` type that tracks the requested offset.
17///
18/// # Safety
19///
20/// Buffers passed to `io-uring` operations must reference a stable memory
21/// region. While the runtime holds ownership to a buffer, the pointer returned
22/// by `stable_ptr` must remain valid even if the `IoBuf` value is moved.
23///
24/// [`slice()`]: IoBuf::slice
25pub unsafe trait IoBuf: Unpin + 'static {
26    /// Returns a raw pointer to the vector’s buffer.
27    ///
28    /// This method is to be used by the `tokio-uring` runtime and it is not
29    /// expected for users to call it directly.
30    ///
31    /// The implementation must ensure that, while the `tokio-uring` runtime
32    /// owns the value, the pointer returned by `stable_ptr` **does not**
33    /// change.
34    fn stable_ptr(&self) -> *const u8;
35
36    /// Number of initialized bytes.
37    ///
38    /// This method is to be used by the `tokio-uring` runtime and it is not
39    /// expected for users to call it directly.
40    ///
41    /// For `Vec`, this is identical to `len()`.
42    fn bytes_init(&self) -> usize;
43
44    /// Total size of the buffer, including uninitialized memory, if any.
45    ///
46    /// This method is to be used by the `tokio-uring` runtime and it is not
47    /// expected for users to call it directly.
48    ///
49    /// For `Vec`, this is identical to `capacity()`.
50    fn bytes_total(&self) -> usize;
51
52    /// Returns a view of the buffer with the specified range.
53    ///
54    /// This method is similar to Rust's slicing (`&buf[..]`), but takes
55    /// ownership of the buffer.
56    ///
57    /// # Examples
58    ///
59    /// ```
60    /// use tokio_uring::buf::IoBuf;
61    ///
62    /// let buf = b"hello world".to_vec();
63    /// buf.slice(5..10);
64    /// ```
65    fn slice(self, range: impl ops::RangeBounds<usize>) -> Slice<Self>
66    where
67        Self: Sized,
68    {
69        use core::ops::Bound;
70
71        let begin = match range.start_bound() {
72            Bound::Included(&n) => n,
73            Bound::Excluded(&n) => n + 1,
74            Bound::Unbounded => 0,
75        };
76
77        assert!(begin < self.bytes_total());
78
79        let end = match range.end_bound() {
80            Bound::Included(&n) => n.checked_add(1).expect("out of range"),
81            Bound::Excluded(&n) => n,
82            Bound::Unbounded => self.bytes_total(),
83        };
84
85        assert!(end <= self.bytes_total());
86        assert!(begin <= self.bytes_init());
87
88        Slice::new(self, begin, end)
89    }
90}
91
92unsafe impl IoBuf for Vec<u8> {
93    fn stable_ptr(&self) -> *const u8 {
94        self.as_ptr()
95    }
96
97    fn bytes_init(&self) -> usize {
98        self.len()
99    }
100
101    fn bytes_total(&self) -> usize {
102        self.capacity()
103    }
104}
105
106unsafe impl IoBuf for &'static [u8] {
107    fn stable_ptr(&self) -> *const u8 {
108        self.as_ptr()
109    }
110
111    fn bytes_init(&self) -> usize {
112        <[u8]>::len(self)
113    }
114
115    fn bytes_total(&self) -> usize {
116        self.bytes_init()
117    }
118}
119
120unsafe impl IoBuf for &'static str {
121    fn stable_ptr(&self) -> *const u8 {
122        self.as_ptr()
123    }
124
125    fn bytes_init(&self) -> usize {
126        <str>::len(self)
127    }
128
129    fn bytes_total(&self) -> usize {
130        self.bytes_init()
131    }
132}
133
134#[cfg(feature = "bytes")]
135unsafe impl IoBuf for bytes::Bytes {
136    fn stable_ptr(&self) -> *const u8 {
137        self.as_ptr()
138    }
139
140    fn bytes_init(&self) -> usize {
141        self.len()
142    }
143
144    fn bytes_total(&self) -> usize {
145        self.len()
146    }
147}
148
149#[cfg(feature = "bytes")]
150unsafe impl IoBuf for bytes::BytesMut {
151    fn stable_ptr(&self) -> *const u8 {
152        self.as_ptr()
153    }
154
155    fn bytes_init(&self) -> usize {
156        self.len()
157    }
158
159    fn bytes_total(&self) -> usize {
160        self.capacity()
161    }
162}