compio_buf/
io_buf.rs

1#[cfg(feature = "allocator_api")]
2use std::alloc::Allocator;
3use std::{mem::MaybeUninit, rc::Rc, sync::Arc};
4
5use crate::*;
6
7/// A trait for buffers.
8///
9/// The `IoBuf` trait is implemented by buffer types that can be passed to
10/// compio operations. Users will not need to use this trait directly.
11///
12/// # Safety
13///
14/// The implementer should ensure the pointer, len and capacity are valid, so
15/// that the returned slice of [`IoBuf::as_slice`] is valid.
16pub unsafe trait IoBuf: 'static {
17    /// Returns a raw pointer to the vector’s buffer.
18    ///
19    /// This method is to be used by the `compio` runtime and it is not
20    /// expected for users to call it directly.
21    fn as_buf_ptr(&self) -> *const u8;
22
23    /// Number of initialized bytes.
24    ///
25    /// This method is to be used by the `compio` runtime and it is not
26    /// expected for users to call it directly.
27    ///
28    /// For [`Vec`], this is identical to `len()`.
29    fn buf_len(&self) -> usize;
30
31    /// Total size of the buffer, including uninitialized memory, if any.
32    ///
33    /// This method is to be used by the `compio` runtime and it is not
34    /// expected for users to call it directly.
35    ///
36    /// For [`Vec`], this is identical to `capacity()`.
37    fn buf_capacity(&self) -> usize;
38
39    /// Get the initialized part of the buffer.
40    fn as_slice(&self) -> &[u8] {
41        unsafe { std::slice::from_raw_parts(self.as_buf_ptr(), self.buf_len()) }
42    }
43
44    /// Create an [`IoSlice`] of this buffer.
45    ///
46    /// # Safety
47    ///
48    /// The return slice will not live longer than `Self`.
49    /// It is static to provide convenience from writing self-referenced
50    /// structure.
51    unsafe fn as_io_slice(&self) -> IoSlice {
52        IoSlice::from_slice(self.as_slice())
53    }
54
55    /// Returns a view of the buffer with the specified range.
56    ///
57    /// This method is similar to Rust's slicing (`&buf[..]`), but takes
58    /// ownership of the buffer.
59    ///
60    /// # Examples
61    ///
62    /// ```
63    /// use compio_buf::IoBuf;
64    ///
65    /// let buf = b"hello world";
66    /// assert_eq!(buf.slice(6..).as_slice(), b"world");
67    /// ```
68    fn slice(self, range: impl std::ops::RangeBounds<usize>) -> Slice<Self>
69    where
70        Self: Sized,
71    {
72        use std::ops::Bound;
73
74        let begin = match range.start_bound() {
75            Bound::Included(&n) => n,
76            Bound::Excluded(&n) => n + 1,
77            Bound::Unbounded => 0,
78        };
79
80        assert!(begin <= self.buf_capacity());
81
82        let end = match range.end_bound() {
83            Bound::Included(&n) => n.checked_add(1).expect("out of range"),
84            Bound::Excluded(&n) => n,
85            Bound::Unbounded => self.buf_capacity(),
86        };
87
88        assert!(end <= self.buf_capacity());
89        assert!(begin <= self.buf_len());
90
91        Slice::new(self, begin, end)
92    }
93
94    /// Indicate whether the buffer has been filled (uninit portion is empty)
95    fn filled(&self) -> bool {
96        self.buf_len() == self.buf_capacity()
97    }
98}
99
100unsafe impl<B: IoBuf + ?Sized> IoBuf for &'static B {
101    fn as_buf_ptr(&self) -> *const u8 {
102        (**self).as_buf_ptr()
103    }
104
105    fn buf_len(&self) -> usize {
106        (**self).buf_len()
107    }
108
109    fn buf_capacity(&self) -> usize {
110        (**self).buf_capacity()
111    }
112}
113
114unsafe impl<B: IoBuf + ?Sized> IoBuf for &'static mut B {
115    fn as_buf_ptr(&self) -> *const u8 {
116        (**self).as_buf_ptr()
117    }
118
119    fn buf_len(&self) -> usize {
120        (**self).buf_len()
121    }
122
123    fn buf_capacity(&self) -> usize {
124        (**self).buf_capacity()
125    }
126}
127
128unsafe impl<B: IoBuf + ?Sized, #[cfg(feature = "allocator_api")] A: Allocator + 'static> IoBuf
129    for t_alloc!(Box, B, A)
130{
131    fn as_buf_ptr(&self) -> *const u8 {
132        (**self).as_buf_ptr()
133    }
134
135    fn buf_len(&self) -> usize {
136        (**self).buf_len()
137    }
138
139    fn buf_capacity(&self) -> usize {
140        (**self).buf_capacity()
141    }
142}
143
144unsafe impl<B: IoBuf + ?Sized, #[cfg(feature = "allocator_api")] A: Allocator + 'static> IoBuf
145    for t_alloc!(Rc, B, A)
146{
147    fn as_buf_ptr(&self) -> *const u8 {
148        (**self).as_buf_ptr()
149    }
150
151    fn buf_len(&self) -> usize {
152        (**self).buf_len()
153    }
154
155    fn buf_capacity(&self) -> usize {
156        (**self).buf_capacity()
157    }
158}
159
160unsafe impl<B: IoBuf + ?Sized, #[cfg(feature = "allocator_api")] A: Allocator + 'static> IoBuf
161    for t_alloc!(Arc, B, A)
162{
163    fn as_buf_ptr(&self) -> *const u8 {
164        (**self).as_buf_ptr()
165    }
166
167    fn buf_len(&self) -> usize {
168        (**self).buf_len()
169    }
170
171    fn buf_capacity(&self) -> usize {
172        (**self).buf_capacity()
173    }
174}
175
176unsafe impl<#[cfg(feature = "allocator_api")] A: Allocator + 'static> IoBuf
177    for t_alloc!(Vec, u8, A)
178{
179    fn as_buf_ptr(&self) -> *const u8 {
180        self.as_ptr()
181    }
182
183    fn buf_len(&self) -> usize {
184        self.len()
185    }
186
187    fn buf_capacity(&self) -> usize {
188        self.capacity()
189    }
190}
191
192unsafe impl IoBuf for String {
193    fn as_buf_ptr(&self) -> *const u8 {
194        self.as_ptr()
195    }
196
197    fn buf_len(&self) -> usize {
198        self.len()
199    }
200
201    fn buf_capacity(&self) -> usize {
202        self.capacity()
203    }
204}
205
206unsafe impl IoBuf for str {
207    fn as_buf_ptr(&self) -> *const u8 {
208        self.as_ptr()
209    }
210
211    fn buf_len(&self) -> usize {
212        self.len()
213    }
214
215    fn buf_capacity(&self) -> usize {
216        self.len()
217    }
218}
219
220unsafe impl IoBuf for [u8] {
221    fn as_buf_ptr(&self) -> *const u8 {
222        self.as_ptr()
223    }
224
225    fn buf_len(&self) -> usize {
226        self.len()
227    }
228
229    fn buf_capacity(&self) -> usize {
230        self.len()
231    }
232}
233
234unsafe impl<const N: usize> IoBuf for [u8; N] {
235    fn as_buf_ptr(&self) -> *const u8 {
236        self.as_ptr()
237    }
238
239    fn buf_len(&self) -> usize {
240        N
241    }
242
243    fn buf_capacity(&self) -> usize {
244        N
245    }
246}
247
248#[cfg(feature = "bytes")]
249unsafe impl IoBuf for bytes::Bytes {
250    fn as_buf_ptr(&self) -> *const u8 {
251        self.as_ptr()
252    }
253
254    fn buf_len(&self) -> usize {
255        self.len()
256    }
257
258    fn buf_capacity(&self) -> usize {
259        self.len()
260    }
261}
262
263#[cfg(feature = "bytes")]
264unsafe impl IoBuf for bytes::BytesMut {
265    fn as_buf_ptr(&self) -> *const u8 {
266        self.as_ptr()
267    }
268
269    fn buf_len(&self) -> usize {
270        self.len()
271    }
272
273    fn buf_capacity(&self) -> usize {
274        self.capacity()
275    }
276}
277
278#[cfg(feature = "read_buf")]
279unsafe impl IoBuf for std::io::BorrowedBuf<'static> {
280    fn as_buf_ptr(&self) -> *const u8 {
281        self.filled().as_ptr()
282    }
283
284    fn buf_len(&self) -> usize {
285        self.len()
286    }
287
288    fn buf_capacity(&self) -> usize {
289        self.capacity()
290    }
291}
292
293#[cfg(feature = "arrayvec")]
294unsafe impl<const N: usize> IoBuf for arrayvec::ArrayVec<u8, N> {
295    fn as_buf_ptr(&self) -> *const u8 {
296        self.as_ptr()
297    }
298
299    fn buf_len(&self) -> usize {
300        self.len()
301    }
302
303    fn buf_capacity(&self) -> usize {
304        self.capacity()
305    }
306}
307
308#[cfg(feature = "smallvec")]
309unsafe impl<const N: usize> IoBuf for smallvec::SmallVec<[u8; N]>
310where
311    [u8; N]: smallvec::Array<Item = u8>,
312{
313    fn as_buf_ptr(&self) -> *const u8 {
314        self.as_ptr()
315    }
316
317    fn buf_len(&self) -> usize {
318        self.len()
319    }
320
321    fn buf_capacity(&self) -> usize {
322        self.capacity()
323    }
324}
325
326/// A mutable compio compatible buffer.
327///
328/// The `IoBufMut` trait is implemented by buffer types that can be passed to
329/// compio operations. Users will not need to use this trait directly.
330///
331/// # Safety
332///
333/// Buffers passed to compio operations must reference a stable memory
334/// region. While the runtime holds ownership to a buffer, the pointer returned
335/// by `as_buf_mut_ptr` must remain valid even if the `IoBufMut` value is moved.
336pub unsafe trait IoBufMut: IoBuf + SetBufInit {
337    /// Returns a raw mutable pointer to the vector’s buffer.
338    ///
339    /// This method is to be used by the `compio` runtime and it is not
340    /// expected for users to call it directly.
341    fn as_buf_mut_ptr(&mut self) -> *mut u8;
342
343    /// Get the uninitialized part of the buffer.
344    fn as_mut_slice(&mut self) -> &mut [MaybeUninit<u8>] {
345        unsafe {
346            std::slice::from_raw_parts_mut(self.as_buf_mut_ptr().cast(), (*self).buf_capacity())
347        }
348    }
349
350    /// Create an [`IoSliceMut`] of the uninitialized part of the buffer.
351    ///
352    /// # Safety
353    ///
354    /// The return slice will not live longer than self.
355    /// It is static to provide convenience from writing self-referenced
356    /// structure.
357    unsafe fn as_io_slice_mut(&mut self) -> IoSliceMut {
358        IoSliceMut::from_uninit(self.as_mut_slice())
359    }
360}
361
362unsafe impl<B: IoBufMut + ?Sized> IoBufMut for &'static mut B {
363    fn as_buf_mut_ptr(&mut self) -> *mut u8 {
364        (**self).as_buf_mut_ptr()
365    }
366}
367
368unsafe impl<B: IoBufMut + ?Sized, #[cfg(feature = "allocator_api")] A: Allocator + 'static> IoBufMut
369    for t_alloc!(Box, B, A)
370{
371    fn as_buf_mut_ptr(&mut self) -> *mut u8 {
372        (**self).as_buf_mut_ptr()
373    }
374}
375
376unsafe impl<#[cfg(feature = "allocator_api")] A: Allocator + 'static> IoBufMut
377    for t_alloc!(Vec, u8, A)
378{
379    fn as_buf_mut_ptr(&mut self) -> *mut u8 {
380        self.as_mut_ptr()
381    }
382}
383
384unsafe impl IoBufMut for [u8] {
385    fn as_buf_mut_ptr(&mut self) -> *mut u8 {
386        self.as_mut_ptr()
387    }
388}
389
390unsafe impl<const N: usize> IoBufMut for [u8; N] {
391    fn as_buf_mut_ptr(&mut self) -> *mut u8 {
392        self.as_mut_ptr()
393    }
394}
395
396#[cfg(feature = "bytes")]
397unsafe impl IoBufMut for bytes::BytesMut {
398    fn as_buf_mut_ptr(&mut self) -> *mut u8 {
399        self.as_mut_ptr()
400    }
401}
402
403#[cfg(feature = "read_buf")]
404unsafe impl IoBufMut for std::io::BorrowedBuf<'static> {
405    fn as_buf_mut_ptr(&mut self) -> *mut u8 {
406        (*self).filled().as_ptr() as _
407    }
408}
409
410#[cfg(feature = "arrayvec")]
411unsafe impl<const N: usize> IoBufMut for arrayvec::ArrayVec<u8, N> {
412    fn as_buf_mut_ptr(&mut self) -> *mut u8 {
413        self.as_mut_ptr()
414    }
415}
416
417#[cfg(feature = "smallvec")]
418unsafe impl<const N: usize> IoBufMut for smallvec::SmallVec<[u8; N]>
419where
420    [u8; N]: smallvec::Array<Item = u8>,
421{
422    fn as_buf_mut_ptr(&mut self) -> *mut u8 {
423        self.as_mut_ptr()
424    }
425}
426
427/// A helper trait for `set_len` like methods.
428pub trait SetBufInit {
429    /// Set the buffer length. If `len` is less than the current length, nothing
430    /// should happen.
431    ///
432    /// # Safety
433    ///
434    /// `len` should be less or equal than `buf_capacity()`.
435    unsafe fn set_buf_init(&mut self, len: usize);
436}
437
438impl<B: SetBufInit + ?Sized> SetBufInit for &'static mut B {
439    unsafe fn set_buf_init(&mut self, len: usize) {
440        (**self).set_buf_init(len)
441    }
442}
443
444impl<B: SetBufInit + ?Sized, #[cfg(feature = "allocator_api")] A: Allocator + 'static> SetBufInit
445    for t_alloc!(Box, B, A)
446{
447    unsafe fn set_buf_init(&mut self, len: usize) {
448        (**self).set_buf_init(len)
449    }
450}
451
452impl<#[cfg(feature = "allocator_api")] A: Allocator + 'static> SetBufInit for t_alloc!(Vec, u8, A) {
453    unsafe fn set_buf_init(&mut self, len: usize) {
454        if (**self).buf_len() < len {
455            self.set_len(len);
456        }
457    }
458}
459
460impl SetBufInit for [u8] {
461    unsafe fn set_buf_init(&mut self, len: usize) {
462        debug_assert!(len <= self.len());
463    }
464}
465
466impl<const N: usize> SetBufInit for [u8; N] {
467    unsafe fn set_buf_init(&mut self, len: usize) {
468        debug_assert!(len <= N);
469    }
470}
471
472#[cfg(feature = "bytes")]
473impl SetBufInit for bytes::BytesMut {
474    unsafe fn set_buf_init(&mut self, len: usize) {
475        if (**self).buf_len() < len {
476            self.set_len(len);
477        }
478    }
479}
480
481#[cfg(feature = "read_buf")]
482impl SetBufInit for std::io::BorrowedBuf<'static> {
483    unsafe fn set_buf_init(&mut self, len: usize) {
484        let current_len = (*self).buf_len();
485        if current_len < len {
486            self.unfilled().advance(len - current_len);
487        }
488    }
489}
490
491#[cfg(feature = "arrayvec")]
492impl<const N: usize> SetBufInit for arrayvec::ArrayVec<u8, N> {
493    unsafe fn set_buf_init(&mut self, len: usize) {
494        if (**self).buf_len() < len {
495            self.set_len(len);
496        }
497    }
498}
499
500#[cfg(feature = "smallvec")]
501impl<const N: usize> SetBufInit for smallvec::SmallVec<[u8; N]>
502where
503    [u8; N]: smallvec::Array<Item = u8>,
504{
505    unsafe fn set_buf_init(&mut self, len: usize) {
506        if (**self).buf_len() < len {
507            self.set_len(len);
508        }
509    }
510}
511
512impl<T: IoBufMut> SetBufInit for [T] {
513    unsafe fn set_buf_init(&mut self, len: usize) {
514        default_set_buf_init(self.iter_mut(), len)
515    }
516}
517
518impl<T: IoBufMut, const N: usize> SetBufInit for [T; N] {
519    unsafe fn set_buf_init(&mut self, len: usize) {
520        default_set_buf_init(self.iter_mut(), len)
521    }
522}
523
524impl<T: IoBufMut, #[cfg(feature = "allocator_api")] A: Allocator + 'static> SetBufInit
525    for t_alloc!(Vec, T, A)
526{
527    unsafe fn set_buf_init(&mut self, len: usize) {
528        default_set_buf_init(self.iter_mut(), len)
529    }
530}
531
532#[cfg(feature = "arrayvec")]
533impl<T: IoBufMut, const N: usize> SetBufInit for arrayvec::ArrayVec<T, N> {
534    unsafe fn set_buf_init(&mut self, len: usize) {
535        default_set_buf_init(self.iter_mut(), len)
536    }
537}
538
539#[cfg(feature = "smallvec")]
540impl<T: IoBufMut, const N: usize> SetBufInit for smallvec::SmallVec<[T; N]>
541where
542    [T; N]: smallvec::Array<Item = T>,
543{
544    unsafe fn set_buf_init(&mut self, len: usize) {
545        default_set_buf_init(self.iter_mut(), len)
546    }
547}
548
549unsafe fn default_set_buf_init<'a, B: IoBufMut>(
550    iter: impl IntoIterator<Item = &'a mut B>,
551    mut len: usize,
552) {
553    for buf in iter {
554        let capacity = (*buf).buf_capacity();
555        if len >= capacity {
556            buf.set_buf_init(capacity);
557            len -= capacity;
558        } else {
559            buf.set_buf_init(len);
560            len = 0;
561        }
562    }
563}