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}