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
use crate::buf::Slice;
use std::ops;
/// An `io-uring` compatible buffer.
///
/// The `IoBuf` trait is implemented by buffer types that can be passed to
/// io-uring operations. Users will not need to use this trait directly, except
/// for the [`slice`] method.
///
/// # Slicing
///
/// Because buffers are passed by ownership to the runtime, Rust's slice API
/// (`&buf[..]`) cannot be used. Instead, `tokio-uring` provides an owned slice
/// API: [`slice()`]. The method takes ownership fo the buffer and returns a
/// `Slice<Self>` type that tracks the requested offset.
///
/// # Safety
///
/// Buffers passed to `io-uring` operations must reference a stable memory
/// region. While the runtime holds ownership to a buffer, the pointer returned
/// by `stable_ptr` must remain valid even if the `IoBuf` value is moved.
///
/// [`slice()`]: IoBuf::slice
pub unsafe trait IoBuf: Unpin + 'static {
/// Returns a raw pointer to the vector’s buffer.
///
/// This method is to be used by the `tokio-uring` runtime and it is not
/// expected for users to call it directly.
///
/// The implementation must ensure that, while the `tokio-uring` runtime
/// owns the value, the pointer returned by `stable_ptr` **does not**
/// change.
fn stable_ptr(&self) -> *const u8;
/// Number of initialized bytes.
///
/// This method is to be used by the `tokio-uring` runtime and it is not
/// expected for users to call it directly.
///
/// For `Vec`, this is identical to `len()`.
fn bytes_init(&self) -> usize;
/// Total size of the buffer, including uninitialized memory, if any.
///
/// This method is to be used by the `tokio-uring` runtime and it is not
/// expected for users to call it directly.
///
/// For `Vec`, this is identical to `capacity()`.
fn bytes_total(&self) -> usize;
/// Returns a view of the buffer with the specified range.
///
/// This method is similar to Rust's slicing (`&buf[..]`), but takes
/// ownership of the buffer.
///
/// # Examples
///
/// ```
/// use tokio_uring::buf::IoBuf;
///
/// let buf = b"hello world".to_vec();
/// buf.slice(5..10);
/// ```
fn slice(self, range: impl ops::RangeBounds<usize>) -> Slice<Self>
where
Self: Sized,
{
use core::ops::Bound;
let begin = match range.start_bound() {
Bound::Included(&n) => n,
Bound::Excluded(&n) => n + 1,
Bound::Unbounded => 0,
};
assert!(begin < self.bytes_total());
let end = match range.end_bound() {
Bound::Included(&n) => n.checked_add(1).expect("out of range"),
Bound::Excluded(&n) => n,
Bound::Unbounded => self.bytes_total(),
};
assert!(end <= self.bytes_total());
assert!(begin <= self.bytes_init());
Slice::new(self, begin, end)
}
}
unsafe impl IoBuf for Vec<u8> {
fn stable_ptr(&self) -> *const u8 {
self.as_ptr()
}
fn bytes_init(&self) -> usize {
self.len()
}
fn bytes_total(&self) -> usize {
self.capacity()
}
}
unsafe impl IoBuf for &'static [u8] {
fn stable_ptr(&self) -> *const u8 {
self.as_ptr()
}
fn bytes_init(&self) -> usize {
<[u8]>::len(self)
}
fn bytes_total(&self) -> usize {
self.bytes_init()
}
}
unsafe impl IoBuf for &'static str {
fn stable_ptr(&self) -> *const u8 {
self.as_ptr()
}
fn bytes_init(&self) -> usize {
<str>::len(self)
}
fn bytes_total(&self) -> usize {
self.bytes_init()
}
}
#[cfg(feature = "bytes")]
unsafe impl IoBuf for bytes::Bytes {
fn stable_ptr(&self) -> *const u8 {
self.as_ptr()
}
fn bytes_init(&self) -> usize {
self.len()
}
fn bytes_total(&self) -> usize {
self.len()
}
}
#[cfg(feature = "bytes")]
unsafe impl IoBuf for bytes::BytesMut {
fn stable_ptr(&self) -> *const u8 {
self.as_ptr()
}
fn bytes_init(&self) -> usize {
self.len()
}
fn bytes_total(&self) -> usize {
self.capacity()
}
}