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 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
use super::{IoBuf, IoBufMut, Slice};
use std::ops;
use std::ptr;
/// A possibly bounded view into an owned [`IoBuf`] buffer.
///
/// 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 of the buffer and returns a
/// [`Slice`] value that tracks the requested range.
///
/// This trait provides a generic way to use buffers and `Slice` views
/// into such buffers with `io-uring` operations.
///
/// [`.slice()`]: BoundedBuf::slice
pub trait BoundedBuf: Unpin + 'static {
/// The type of the underlying buffer.
type Buf: IoBuf;
/// The type representing the range bounds of the view.
type Bounds: ops::RangeBounds<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. The range bounds are specified against
/// the possibly offset beginning of the `self` view into the buffer
/// and the end bound, if specified, must not exceed the view's total size.
/// Note that the range may extend into the uninitialized part of the
/// buffer, but it must start (if so bounded) in the initialized part
/// or immediately adjacent to it.
///
/// # Panics
///
/// If the range is invalid with regard to the recipient's total size or
/// the length of its initialized part, the implementation of this method
/// should panic.
///
/// # Examples
///
/// ```
/// use tokio_uring::buf::BoundedBuf;
///
/// let buf = b"hello world".to_vec();
/// let slice = buf.slice(5..10);
/// assert_eq!(&slice[..], b" worl");
/// let slice = slice.slice(1..3);
/// assert_eq!(&slice[..], b"wo");
/// ```
fn slice(self, range: impl ops::RangeBounds<usize>) -> Slice<Self::Buf>;
/// Returns a `Slice` with the view's full range.
///
/// This method is to be used by the `tokio-uring` runtime and it is not
/// expected for users to call it directly.
fn slice_full(self) -> Slice<Self::Buf>;
/// Gets a reference to the underlying buffer.
fn get_buf(&self) -> &Self::Buf;
/// Returns the range bounds for this view.
fn bounds(&self) -> Self::Bounds;
/// Constructs a view from an underlying buffer and range bounds.
fn from_buf_bounds(buf: Self::Buf, bounds: Self::Bounds) -> Self;
/// Like [`IoBuf::stable_ptr`],
/// but possibly offset to the view's starting position.
fn stable_ptr(&self) -> *const u8;
/// Number of initialized bytes available via this view.
fn bytes_init(&self) -> usize;
/// Total size of the view, including uninitialized memory, if any.
fn bytes_total(&self) -> usize;
}
impl<T: IoBuf> BoundedBuf for T {
type Buf = Self;
type Bounds = ops::RangeFull;
fn slice(self, range: impl ops::RangeBounds<usize>) -> Slice<Self> {
use ops::Bound;
let begin = match range.start_bound() {
Bound::Included(&n) => n,
Bound::Excluded(&n) => n.checked_add(1).expect("out of range"),
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)
}
fn slice_full(self) -> Slice<Self> {
let end = self.bytes_total();
Slice::new(self, 0, end)
}
fn get_buf(&self) -> &Self {
self
}
fn bounds(&self) -> Self::Bounds {
..
}
fn from_buf_bounds(buf: Self, _: ops::RangeFull) -> Self {
buf
}
fn stable_ptr(&self) -> *const u8 {
IoBuf::stable_ptr(self)
}
fn bytes_init(&self) -> usize {
IoBuf::bytes_init(self)
}
fn bytes_total(&self) -> usize {
IoBuf::bytes_total(self)
}
}
/// A possibly bounded view into an owned [`IoBufMut`] buffer.
///
/// This trait provides a generic way to use mutable buffers and `Slice` views
/// into such buffers with `io-uring` operations.
pub trait BoundedBufMut: BoundedBuf<Buf = Self::BufMut> {
/// The type of the underlying buffer.
type BufMut: IoBufMut;
/// Like [`IoBufMut::stable_mut_ptr`],
/// but possibly offset to the view's starting position.
fn stable_mut_ptr(&mut self) -> *mut u8;
/// Like [`IoBufMut::set_init`],
/// but the position is possibly offset to the view's starting position.
///
/// # Safety
///
/// The caller must ensure that all bytes starting at `stable_mut_ptr()` up
/// to `pos` are initialized and owned by the buffer.
unsafe fn set_init(&mut self, pos: usize);
/// Copies the given byte slice into the buffer, starting at
/// this view's offset.
///
/// # Panics
///
/// If the slice's length exceeds the destination's total capacity,
/// this method panics.
fn put_slice(&mut self, src: &[u8]) {
assert!(self.bytes_total() >= src.len());
let dst = self.stable_mut_ptr();
// Safety:
// dst pointer validity is ensured by stable_mut_ptr;
// the length is checked to not exceed the view's total capacity;
// src (immutable) and dst (mutable) cannot point to overlapping memory;
// after copying the amount of bytes given by the slice, it's safe
// to mark them as initialized in the buffer.
unsafe {
ptr::copy_nonoverlapping(src.as_ptr(), dst, src.len());
self.set_init(src.len());
}
}
}
impl<T: IoBufMut> BoundedBufMut for T {
type BufMut = T;
fn stable_mut_ptr(&mut self) -> *mut u8 {
IoBufMut::stable_mut_ptr(self)
}
unsafe fn set_init(&mut self, pos: usize) {
IoBufMut::set_init(self, pos)
}
}