Skip to main content

compio_buf/
io_buf.rs

1#[cfg(feature = "allocator_api")]
2use std::alloc::Allocator;
3use std::{error::Error, fmt::Display, mem::MaybeUninit, ops::RangeBounds, rc::Rc, sync::Arc};
4
5use crate::*;
6
7/// A trait for immutable buffers.
8///
9/// The `IoBuf` trait is implemented by buffer types that can be passed to
10/// immutable completion-based IO operations, like writing its content to a
11/// file. This trait will only take initialized bytes of a buffer into account.
12pub trait IoBuf: 'static {
13    /// Get the slice of initialized bytes.
14    fn as_init(&self) -> &[u8];
15
16    /// Length of initialized bytes in the buffer.
17    fn buf_len(&self) -> usize {
18        self.as_init().len()
19    }
20
21    /// Raw pointer to the buffer.
22    fn buf_ptr(&self) -> *const u8 {
23        self.as_init().as_ptr()
24    }
25
26    /// Check if the buffer is empty.
27    fn is_empty(&self) -> bool {
28        self.buf_len() == 0
29    }
30
31    /// Returns a view of the buffer with the specified range.
32    ///
33    /// This method is similar to Rust's slicing (`&buf[..]`), but takes
34    /// ownership of the buffer.
35    ///
36    /// # Examples
37    ///
38    /// ```
39    /// use compio_buf::IoBuf;
40    ///
41    /// let buf = b"hello world";
42    /// assert_eq!(buf.slice(6..).as_init(), b"world");
43    /// ```
44    ///
45    /// # Panics
46    /// Panics if:
47    /// * begin > buf_len()
48    /// * end < begin
49    fn slice(self, range: impl std::ops::RangeBounds<usize>) -> Slice<Self>
50    where
51        Self: Sized,
52    {
53        use std::ops::Bound;
54
55        let begin = match range.start_bound() {
56            Bound::Included(&n) => n,
57            Bound::Excluded(&n) => n + 1,
58            Bound::Unbounded => 0,
59        };
60
61        let end = match range.end_bound() {
62            Bound::Included(&n) => Some(n.checked_add(1).expect("out of range")),
63            Bound::Excluded(&n) => Some(n),
64            Bound::Unbounded => None,
65        };
66
67        assert!(begin <= self.buf_len());
68
69        if let Some(end) = end {
70            assert!(begin <= end);
71        }
72
73        // SAFETY: begin <= self.buf_len()
74        unsafe { Slice::new(self, begin, end) }
75    }
76
77    /// Create a [`Reader`] from this buffer, which implements
78    /// [`std::io::Read`].
79    fn into_reader(self) -> Reader<Self>
80    where
81        Self: Sized,
82    {
83        Reader::new(self)
84    }
85
86    /// Create a [`ReaderRef`] from a reference of the buffer, which
87    /// implements [`std::io::Read`].
88    fn as_reader(&self) -> ReaderRef<'_, Self> {
89        ReaderRef::new(self)
90    }
91}
92
93impl<B: IoBuf + ?Sized> IoBuf for &'static B {
94    fn as_init(&self) -> &[u8] {
95        (**self).as_init()
96    }
97}
98
99impl<B: IoBuf + ?Sized> IoBuf for &'static mut B {
100    fn as_init(&self) -> &[u8] {
101        (**self).as_init()
102    }
103}
104
105impl<B: IoBuf + ?Sized, #[cfg(feature = "allocator_api")] A: Allocator + 'static> IoBuf
106    for t_alloc!(Box, B, A)
107{
108    fn as_init(&self) -> &[u8] {
109        (**self).as_init()
110    }
111}
112
113impl<B: IoBuf + ?Sized, #[cfg(feature = "allocator_api")] A: Allocator + 'static> IoBuf
114    for t_alloc!(Rc, B, A)
115{
116    fn as_init(&self) -> &[u8] {
117        (**self).as_init()
118    }
119}
120
121impl IoBuf for [u8] {
122    fn as_init(&self) -> &[u8] {
123        self
124    }
125}
126
127impl<const N: usize> IoBuf for [u8; N] {
128    fn as_init(&self) -> &[u8] {
129        self
130    }
131}
132
133impl<#[cfg(feature = "allocator_api")] A: Allocator + 'static> IoBuf for t_alloc!(Vec, u8, A) {
134    fn as_init(&self) -> &[u8] {
135        self
136    }
137}
138
139impl IoBuf for str {
140    fn as_init(&self) -> &[u8] {
141        self.as_bytes()
142    }
143}
144
145impl IoBuf for String {
146    fn as_init(&self) -> &[u8] {
147        self.as_bytes()
148    }
149}
150
151impl<B: IoBuf + ?Sized, #[cfg(feature = "allocator_api")] A: Allocator + 'static> IoBuf
152    for t_alloc!(Arc, B, A)
153{
154    fn as_init(&self) -> &[u8] {
155        (**self).as_init()
156    }
157}
158
159#[cfg(feature = "bytes")]
160impl IoBuf for bytes::Bytes {
161    fn as_init(&self) -> &[u8] {
162        self
163    }
164}
165
166#[cfg(feature = "bytes")]
167impl IoBuf for bytes::BytesMut {
168    fn as_init(&self) -> &[u8] {
169        self
170    }
171}
172
173#[cfg(feature = "read_buf")]
174impl IoBuf for std::io::BorrowedBuf<'static> {
175    fn as_init(&self) -> &[u8] {
176        self.filled()
177    }
178}
179
180#[cfg(feature = "arrayvec")]
181impl<const N: usize> IoBuf for arrayvec::ArrayVec<u8, N> {
182    fn as_init(&self) -> &[u8] {
183        self
184    }
185}
186
187#[cfg(feature = "smallvec")]
188impl<const N: usize> IoBuf for smallvec::SmallVec<[u8; N]>
189where
190    [u8; N]: smallvec::Array<Item = u8>,
191{
192    fn as_init(&self) -> &[u8] {
193        self
194    }
195}
196
197/// An error indicating that reserving capacity for a buffer failed.
198#[must_use]
199#[derive(Debug)]
200pub enum ReserveError {
201    /// Reservation is not supported.
202    NotSupported,
203
204    /// Reservation failed.
205    ///
206    /// This is usually caused by out-of-memory.
207    ReserveFailed(Box<dyn Error + Send + Sync>),
208}
209
210impl ReserveError {
211    /// Check if the error is [`NotSupported`].
212    ///
213    /// [`NotSupported`]: ReserveError::NotSupported
214    pub fn is_not_supported(&self) -> bool {
215        matches!(self, ReserveError::NotSupported)
216    }
217}
218
219impl Display for ReserveError {
220    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
221        match self {
222            ReserveError::NotSupported => write!(f, "reservation is not supported"),
223            ReserveError::ReserveFailed(src) => write!(f, "reservation failed: {src}"),
224        }
225    }
226}
227
228impl Error for ReserveError {
229    fn source(&self) -> Option<&(dyn Error + 'static)> {
230        match self {
231            ReserveError::ReserveFailed(src) => Some(src.as_ref()),
232            _ => None,
233        }
234    }
235}
236
237impl From<ReserveError> for std::io::Error {
238    fn from(value: ReserveError) -> Self {
239        match value {
240            ReserveError::NotSupported => {
241                std::io::Error::new(std::io::ErrorKind::Unsupported, "reservation not supported")
242            }
243            ReserveError::ReserveFailed(src) => {
244                std::io::Error::new(std::io::ErrorKind::OutOfMemory, src)
245            }
246        }
247    }
248}
249
250/// An error indicating that reserving exact capacity for a buffer failed.
251#[must_use]
252#[derive(Debug)]
253pub enum ReserveExactError {
254    /// Reservation is not supported.
255    NotSupported,
256
257    /// Reservation failed.
258    ///
259    /// This is usually caused by out-of-memory.
260    ReserveFailed(Box<dyn Error + Send + Sync>),
261
262    /// Reserved size does not match the expected size.
263    ExactSizeMismatch {
264        /// Expected size to reserve
265        expected: usize,
266
267        /// Actual size reserved
268        reserved: usize,
269    },
270}
271
272impl ReserveExactError {
273    /// Check if the error is [`NotSupported`]
274    ///
275    /// [`NotSupported`]: ReserveExactError::NotSupported
276    pub fn is_not_supported(&self) -> bool {
277        matches!(self, ReserveExactError::NotSupported)
278    }
279}
280
281impl Display for ReserveExactError {
282    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
283        match self {
284            ReserveExactError::NotSupported => write!(f, "reservation is not supported"),
285            ReserveExactError::ReserveFailed(src) => write!(f, "reservation failed: {src}"),
286            ReserveExactError::ExactSizeMismatch { reserved, expected } => {
287                write!(
288                    f,
289                    "reserved size mismatch: expected {}, reserved {}",
290                    expected, reserved
291                )
292            }
293        }
294    }
295}
296
297impl From<ReserveError> for ReserveExactError {
298    fn from(err: ReserveError) -> Self {
299        match err {
300            ReserveError::NotSupported => ReserveExactError::NotSupported,
301            ReserveError::ReserveFailed(src) => ReserveExactError::ReserveFailed(src),
302        }
303    }
304}
305
306impl Error for ReserveExactError {
307    fn source(&self) -> Option<&(dyn Error + 'static)> {
308        match self {
309            ReserveExactError::ReserveFailed(src) => Some(src.as_ref()),
310            _ => None,
311        }
312    }
313}
314
315impl From<ReserveExactError> for std::io::Error {
316    fn from(value: ReserveExactError) -> Self {
317        match value {
318            ReserveExactError::NotSupported => {
319                std::io::Error::new(std::io::ErrorKind::Unsupported, "reservation not supported")
320            }
321            ReserveExactError::ReserveFailed(src) => {
322                std::io::Error::new(std::io::ErrorKind::OutOfMemory, src)
323            }
324            ReserveExactError::ExactSizeMismatch { expected, reserved } => std::io::Error::other(
325                format!("reserved size mismatch: expected {expected}, reserved {reserved}",),
326            ),
327        }
328    }
329}
330
331#[cfg(feature = "smallvec")]
332mod smallvec_err {
333    use std::{error::Error, fmt::Display};
334
335    use smallvec::CollectionAllocErr;
336
337    #[derive(Debug)]
338    pub(super) struct SmallVecErr(pub CollectionAllocErr);
339
340    impl Display for SmallVecErr {
341        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
342            write!(f, "SmallVec allocation error: {}", self.0)
343        }
344    }
345
346    impl Error for SmallVecErr {}
347}
348
349/// A trait for mutable buffers.
350///
351/// The `IoBufMut` trait is implemented by buffer types that can be passed to
352/// mutable completion-based IO operations, like reading content from a file and
353/// write to the buffer. This trait will take all space of a buffer into
354/// account, including uninitialized bytes.
355pub trait IoBufMut: IoBuf + SetLen {
356    /// Get the full mutable slice of the buffer, including both initialized
357    /// and uninitialized bytes.
358    fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>];
359
360    /// Total capacity of the buffer, including both initialized and
361    /// uninitialized bytes.
362    fn buf_capacity(&mut self) -> usize {
363        self.as_uninit().len()
364    }
365
366    /// Get the raw mutable pointer to the buffer.
367    fn buf_mut_ptr(&mut self) -> *mut MaybeUninit<u8> {
368        self.as_uninit().as_mut_ptr()
369    }
370
371    /// Get the mutable slice of initialized bytes. The content is the same as
372    /// [`IoBuf::as_init`], but mutable.
373    fn as_mut_slice(&mut self) -> &mut [u8] {
374        let len = (*self).buf_len();
375        let ptr = (*self).buf_mut_ptr();
376        // SAFETY:
377        // - lifetime of the returned slice is bounded by &mut self
378        // - bytes within `len` are guaranteed to be initialized
379        // - the pointer is derived from
380        unsafe { std::slice::from_raw_parts_mut(ptr as *mut u8, len) }
381    }
382
383    /// Extend the buffer by copying bytes from `src`.
384    ///
385    /// The buffer will reserve additional capacity if necessary, and return an
386    /// error when reservation failed.
387    ///
388    /// Notice that this may move the memory of the buffer, so it's UB to
389    /// call this after the buffer is being pinned.
390    // FIXME: Change to `slice::write_copy_of_slice` when stabilized
391    fn extend_from_slice(&mut self, src: &[u8]) -> Result<(), ReserveError> {
392        let len = src.len();
393        let init = (*self).buf_len();
394        self.reserve(len)?;
395        let ptr = self.buf_mut_ptr().wrapping_add(init);
396
397        unsafe {
398            // SAFETY:
399            // - we have reserved enough capacity so the ptr and len stays in one allocation
400            // - src is valid for len bytes
401            // - ptr is valid for len bytes
402            // - &mut self guarantees that src cannot overlap with dst
403            std::ptr::copy_nonoverlapping(src.as_ptr() as _, ptr, len);
404
405            // SAFETY: the bytes in range [init, init + len) are initialized now
406            self.advance_to(init + len);
407        }
408
409        Ok(())
410    }
411
412    /// Like [`slice::copy_within`], copy a range of bytes within the buffer to
413    /// another location in the same buffer. This will count in both initialized
414    /// and uninitialized bytes.
415    ///
416    /// # Panics
417    ///
418    /// This method will panic if the source or destination range is out of
419    /// bounds.
420    ///
421    /// [`slice::copy_within`]: https://doc.rust-lang.org/std/primitive.slice.html#method.copy_within
422    fn copy_within<R>(&mut self, src: R, dest: usize)
423    where
424        R: RangeBounds<usize>,
425    {
426        self.as_uninit().copy_within(src, dest);
427    }
428
429    /// Reserve additional capacity for the buffer.
430    ///
431    /// By default, this checks if the spare capacity is enough to fit in
432    /// `len`-bytes. If it does, returns `Ok(())`, and otherwise returns
433    /// [`Err(ReserveError::NotSupported)`]. Types that support dynamic
434    /// resizing (like `Vec<u8>`) will override this method to actually
435    /// reserve capacity. The return value indicates whether the reservation
436    /// succeeded. See [`ReserveError`] for details.
437    ///
438    /// Notice that this may move the memory of the buffer, so it's UB to
439    /// call this after the buffer is being pinned.
440    ///
441    /// [`Err(ReserveError::NotSupported)`]: ReserveError::NotSupported
442    fn reserve(&mut self, len: usize) -> Result<(), ReserveError> {
443        let init = (*self).buf_len();
444        if len <= self.buf_capacity() - init {
445            return Ok(());
446        }
447        Err(ReserveError::NotSupported)
448    }
449
450    /// Reserve exactly `len` additional capacity for the buffer.
451    ///
452    /// By default this falls back to [`IoBufMut::reserve`]. Types that support
453    /// dynamic resizing (like `Vec<u8>`) will override this method to
454    /// actually reserve capacity. The return value indicates whether the
455    /// exact reservation succeeded. See [`ReserveExactError`] for details.
456    ///
457    /// Notice that this may move the memory of the buffer, so it's UB to
458    /// call this after the buffer is being pinned.
459    fn reserve_exact(&mut self, len: usize) -> Result<(), ReserveExactError> {
460        self.reserve(len)?;
461        Ok(())
462    }
463
464    /// Returns an [`Uninit`], which is a [`Slice`] that only exposes
465    /// uninitialized bytes.
466    ///
467    /// It will always point to the uninitialized area of a [`IoBufMut`] even
468    /// after reading in some bytes, which is done by [`SetLen`]. This
469    /// is useful for writing data into buffer without overwriting any
470    /// existing bytes.
471    ///
472    /// # Examples
473    ///
474    /// ```
475    /// use compio_buf::{IoBuf, IoBufMut};
476    ///
477    /// let mut buf = Vec::from(b"hello world");
478    /// buf.reserve_exact(10);
479    /// let mut slice = buf.uninit();
480    ///
481    /// assert_eq!(slice.as_init(), b"");
482    /// assert_eq!(slice.buf_capacity(), 10);
483    /// ```
484    fn uninit(self) -> Uninit<Self>
485    where
486        Self: Sized,
487    {
488        Uninit::new(self)
489    }
490
491    /// Create a [`Writer`] from this buffer, which implements
492    /// [`std::io::Write`].
493    fn into_writer(self) -> Writer<Self>
494    where
495        Self: Sized,
496    {
497        Writer::new(self)
498    }
499
500    /// Create a [`Writer`] from a mutable reference of the buffer, which
501    /// implements [`std::io::Write`].
502    fn as_writer(&mut self) -> WriterRef<'_, Self> {
503        WriterRef::new(self)
504    }
505
506    /// Indicate whether the buffer has been filled (uninit portion is empty)
507    fn is_filled(&mut self) -> bool {
508        let len = (*self).as_init().len();
509        let cap = (*self).buf_capacity();
510        len == cap
511    }
512}
513
514impl<B: IoBufMut + ?Sized> IoBufMut for &'static mut B {
515    fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
516        (**self).as_uninit()
517    }
518
519    fn reserve(&mut self, len: usize) -> Result<(), ReserveError> {
520        (**self).reserve(len)
521    }
522
523    fn reserve_exact(&mut self, len: usize) -> Result<(), ReserveExactError> {
524        (**self).reserve_exact(len)
525    }
526}
527
528impl<B: IoBufMut + ?Sized, #[cfg(feature = "allocator_api")] A: Allocator + 'static> IoBufMut
529    for t_alloc!(Box, B, A)
530{
531    fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
532        (**self).as_uninit()
533    }
534
535    fn reserve(&mut self, len: usize) -> Result<(), ReserveError> {
536        (**self).reserve(len)
537    }
538
539    fn reserve_exact(&mut self, len: usize) -> Result<(), ReserveExactError> {
540        (**self).reserve_exact(len)
541    }
542}
543
544impl<#[cfg(feature = "allocator_api")] A: Allocator + 'static> IoBufMut for t_alloc!(Vec, u8, A) {
545    fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
546        let ptr = self.as_mut_ptr() as *mut MaybeUninit<u8>;
547        let cap = self.capacity();
548        // SAFETY: Vec guarantees that the pointer is valid for `capacity` bytes
549        unsafe { std::slice::from_raw_parts_mut(ptr, cap) }
550    }
551
552    fn reserve(&mut self, len: usize) -> Result<(), ReserveError> {
553        if let Err(e) = Vec::try_reserve(self, len) {
554            return Err(ReserveError::ReserveFailed(Box::new(e)));
555        }
556
557        Ok(())
558    }
559
560    fn reserve_exact(&mut self, len: usize) -> Result<(), ReserveExactError> {
561        if self.capacity() - self.len() >= len {
562            return Ok(());
563        }
564
565        if let Err(e) = Vec::try_reserve_exact(self, len) {
566            return Err(ReserveExactError::ReserveFailed(Box::new(e)));
567        }
568
569        if self.capacity() - self.len() != len {
570            return Err(ReserveExactError::ExactSizeMismatch {
571                reserved: self.capacity() - self.len(),
572                expected: len,
573            });
574        }
575        Ok(())
576    }
577}
578
579impl IoBufMut for [u8] {
580    fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
581        let ptr = self.as_mut_ptr() as *mut MaybeUninit<u8>;
582        let len = self.len();
583        // SAFETY: slice is fully initialized, so treating it as MaybeUninit is safe
584        unsafe { std::slice::from_raw_parts_mut(ptr, len) }
585    }
586}
587
588impl<const N: usize> IoBufMut for [u8; N] {
589    fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
590        let ptr = self.as_mut_ptr() as *mut MaybeUninit<u8>;
591        // SAFETY: array is fully initialized, so treating it as MaybeUninit is safe
592        unsafe { std::slice::from_raw_parts_mut(ptr, N) }
593    }
594}
595
596#[cfg(feature = "bytes")]
597impl IoBufMut for bytes::BytesMut {
598    fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
599        let ptr = self.as_mut_ptr() as *mut MaybeUninit<u8>;
600        let cap = self.capacity();
601        // SAFETY: BytesMut guarantees that the pointer is valid for `capacity` bytes
602        unsafe { std::slice::from_raw_parts_mut(ptr, cap) }
603    }
604
605    fn reserve(&mut self, len: usize) -> Result<(), ReserveError> {
606        bytes::BytesMut::reserve(self, len);
607        Ok(())
608    }
609
610    fn reserve_exact(&mut self, len: usize) -> Result<(), ReserveExactError> {
611        if self.capacity() - self.len() >= len {
612            return Ok(());
613        }
614
615        bytes::BytesMut::reserve(self, len);
616
617        if self.capacity() - self.len() != len {
618            Err(ReserveExactError::ExactSizeMismatch {
619                reserved: self.capacity() - self.len(),
620                expected: len,
621            })
622        } else {
623            Ok(())
624        }
625    }
626}
627
628#[cfg(feature = "read_buf")]
629impl IoBufMut for std::io::BorrowedBuf<'static> {
630    fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
631        let total_cap = self.capacity();
632
633        // SAFETY: We reconstruct the full buffer from the filled portion pointer.
634        // BorrowedBuf guarantees that the underlying buffer has capacity bytes.
635        unsafe {
636            let filled_ptr = self.filled().as_ptr() as *mut MaybeUninit<u8>;
637            std::slice::from_raw_parts_mut(filled_ptr, total_cap)
638        }
639    }
640}
641
642#[cfg(feature = "arrayvec")]
643impl<const N: usize> IoBufMut for arrayvec::ArrayVec<u8, N> {
644    fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
645        let ptr = self.as_mut_ptr() as *mut MaybeUninit<u8>;
646        // SAFETY: ArrayVec guarantees that the pointer is valid for N bytes
647        unsafe { std::slice::from_raw_parts_mut(ptr, N) }
648    }
649}
650
651#[cfg(feature = "smallvec")]
652impl<const N: usize> IoBufMut for smallvec::SmallVec<[u8; N]>
653where
654    [u8; N]: smallvec::Array<Item = u8>,
655{
656    fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
657        let ptr = self.as_mut_ptr() as *mut MaybeUninit<u8>;
658        let cap = self.capacity();
659        // SAFETY: SmallVec guarantees that the pointer is valid for `capacity` bytes
660        unsafe { std::slice::from_raw_parts_mut(ptr, cap) }
661    }
662
663    fn reserve(&mut self, len: usize) -> Result<(), ReserveError> {
664        if let Err(e) = smallvec::SmallVec::try_reserve(self, len) {
665            return Err(ReserveError::ReserveFailed(Box::new(
666                smallvec_err::SmallVecErr(e),
667            )));
668        }
669        Ok(())
670    }
671
672    fn reserve_exact(&mut self, len: usize) -> Result<(), ReserveExactError> {
673        if self.capacity() - self.len() >= len {
674            return Ok(());
675        }
676
677        if let Err(e) = smallvec::SmallVec::try_reserve_exact(self, len) {
678            return Err(ReserveExactError::ReserveFailed(Box::new(
679                smallvec_err::SmallVecErr(e),
680            )));
681        }
682
683        if self.capacity() - self.len() != len {
684            return Err(ReserveExactError::ExactSizeMismatch {
685                reserved: self.capacity() - self.len(),
686                expected: len,
687            });
688        }
689        Ok(())
690    }
691}
692
693/// A helper trait for `set_len` like methods.
694pub trait SetLen {
695    /// Set the buffer length.
696    ///
697    /// # Safety
698    ///
699    /// * `len` must be less or equal than `as_uninit().len()`.
700    /// * The bytes in the range `[buf_len(), len)` must be initialized.
701    unsafe fn set_len(&mut self, len: usize);
702
703    /// Advance the buffer length by `len`.
704    ///
705    /// # Safety
706    ///
707    /// * The bytes in the range `[buf_len(), buf_len() + len)` must be
708    ///   initialized.
709    unsafe fn advance(&mut self, len: usize)
710    where
711        Self: IoBuf,
712    {
713        let current_len = (*self).buf_len();
714        let new_len = current_len.checked_add(len).expect("length overflow");
715        unsafe { self.set_len(new_len) };
716    }
717
718    /// Set the buffer length to `len`. If `len` is less than the current
719    /// length, this operation is a no-op.
720    ///
721    /// # Safety
722    ///
723    /// * `len` must be less or equal than `as_uninit().len()`.
724    /// * The bytes in the range `[buf_len(), len)` must be initialized.
725    unsafe fn advance_to(&mut self, len: usize)
726    where
727        Self: IoBuf,
728    {
729        let current_len = (*self).buf_len();
730        if len > current_len {
731            unsafe { self.set_len(len) };
732        }
733    }
734
735    /// Set the vector buffer's total length to `len`. If `len` is less than the
736    /// current total length, this operation is a no-op.
737    ///
738    /// # Safety
739    ///
740    /// * `len` must be less or equal than `total_len()`.
741    /// * The bytes in the range `[total_len(), len)` must be initialized.
742    unsafe fn advance_vec_to(&mut self, len: usize)
743    where
744        Self: IoVectoredBuf,
745    {
746        let current_len = (*self).total_len();
747        if len > current_len {
748            unsafe { self.set_len(len) };
749        }
750    }
751
752    /// Clear the buffer, setting its length to 0 without touching its content
753    /// or capacity.
754    fn clear(&mut self)
755    where
756        Self: IoBuf,
757    {
758        // SAFETY: setting length to 0 is always valid
759        unsafe { self.set_len(0) };
760    }
761}
762
763impl<B: SetLen + ?Sized> SetLen for &'static mut B {
764    unsafe fn set_len(&mut self, len: usize) {
765        unsafe { (**self).set_len(len) }
766    }
767}
768
769impl<B: SetLen + ?Sized, #[cfg(feature = "allocator_api")] A: Allocator + 'static> SetLen
770    for t_alloc!(Box, B, A)
771{
772    unsafe fn set_len(&mut self, len: usize) {
773        unsafe { (**self).set_len(len) }
774    }
775}
776
777impl<#[cfg(feature = "allocator_api")] A: Allocator + 'static> SetLen for t_alloc!(Vec, u8, A) {
778    unsafe fn set_len(&mut self, len: usize) {
779        unsafe { self.set_len(len) };
780    }
781}
782
783impl SetLen for [u8] {
784    unsafe fn set_len(&mut self, len: usize) {
785        debug_assert!(len <= self.len());
786    }
787}
788
789impl<const N: usize> SetLen for [u8; N] {
790    unsafe fn set_len(&mut self, len: usize) {
791        debug_assert!(len <= N);
792    }
793}
794
795#[cfg(feature = "bytes")]
796impl SetLen for bytes::BytesMut {
797    unsafe fn set_len(&mut self, len: usize) {
798        unsafe { self.set_len(len) };
799    }
800}
801
802#[cfg(feature = "read_buf")]
803impl SetLen for std::io::BorrowedBuf<'static> {
804    unsafe fn set_len(&mut self, len: usize) {
805        debug_assert!(self.capacity() >= len);
806
807        // SAFETY: `len` range is initialized guaranteed by invariant of `set_len`
808        self.clear().unfilled().advance(len);
809    }
810}
811
812#[cfg(feature = "arrayvec")]
813impl<const N: usize> SetLen for arrayvec::ArrayVec<u8, N> {
814    unsafe fn set_len(&mut self, len: usize) {
815        if (**self).buf_len() < len {
816            unsafe { self.set_len(len) };
817        }
818    }
819}
820
821#[cfg(feature = "smallvec")]
822impl<const N: usize> SetLen for smallvec::SmallVec<[u8; N]>
823where
824    [u8; N]: smallvec::Array<Item = u8>,
825{
826    unsafe fn set_len(&mut self, len: usize) {
827        if (**self).buf_len() < len {
828            unsafe { self.set_len(len) };
829        }
830    }
831}
832
833impl<T: IoBufMut> SetLen for [T] {
834    unsafe fn set_len(&mut self, len: usize) {
835        unsafe { default_set_len(self.iter_mut(), len) }
836    }
837}
838
839impl<T: IoBufMut, const N: usize> SetLen for [T; N] {
840    unsafe fn set_len(&mut self, len: usize) {
841        unsafe { default_set_len(self.iter_mut(), len) }
842    }
843}
844
845impl<T: IoBufMut, #[cfg(feature = "allocator_api")] A: Allocator + 'static> SetLen
846    for t_alloc!(Vec, T, A)
847{
848    unsafe fn set_len(&mut self, len: usize) {
849        unsafe { default_set_len(self.iter_mut(), len) }
850    }
851}
852
853#[cfg(feature = "arrayvec")]
854impl<T: IoBufMut, const N: usize> SetLen for arrayvec::ArrayVec<T, N> {
855    unsafe fn set_len(&mut self, len: usize) {
856        unsafe { default_set_len(self.iter_mut(), len) }
857    }
858}
859
860#[cfg(feature = "smallvec")]
861impl<T: IoBufMut, const N: usize> SetLen for smallvec::SmallVec<[T; N]>
862where
863    [T; N]: smallvec::Array<Item = T>,
864{
865    unsafe fn set_len(&mut self, len: usize) {
866        unsafe { default_set_len(self.iter_mut(), len) }
867    }
868}
869
870/// # Safety
871/// * `len` should be less or equal than the sum of `buf_capacity()` of all
872///   buffers.
873/// * The bytes in the range `[buf_len(), new_len)` of each buffer must be
874///   initialized
875unsafe fn default_set_len<'a, B: IoBufMut>(
876    iter: impl IntoIterator<Item = &'a mut B>,
877    mut len: usize,
878) {
879    let mut iter = iter.into_iter();
880    while len > 0 {
881        let Some(curr) = iter.next() else { return };
882        let sub = (*curr).buf_capacity().min(len);
883        unsafe { curr.set_len(sub) };
884        len -= sub;
885    }
886}
887
888#[cfg(test)]
889mod test {
890    use crate::IoBufMut;
891
892    #[test]
893    fn test_vec_reserve() {
894        let mut buf = Vec::new();
895        IoBufMut::reserve(&mut buf, 10).unwrap();
896        assert!(buf.capacity() >= 10);
897
898        let mut buf = Vec::new();
899        IoBufMut::reserve_exact(&mut buf, 10).unwrap();
900        assert!(buf.capacity() == 10);
901
902        let mut buf = Box::new(Vec::new());
903        IoBufMut::reserve_exact(&mut buf, 10).unwrap();
904        assert!(buf.capacity() == 10);
905    }
906
907    #[test]
908    #[cfg(feature = "bytes")]
909    fn test_bytes_reserve() {
910        let mut buf = bytes::BytesMut::new();
911        IoBufMut::reserve(&mut buf, 10).unwrap();
912        assert!(buf.capacity() >= 10);
913    }
914
915    #[test]
916    #[cfg(feature = "smallvec")]
917    fn test_smallvec_reserve() {
918        let mut buf = smallvec::SmallVec::<[u8; 8]>::new();
919        IoBufMut::reserve(&mut buf, 10).unwrap();
920        assert!(buf.capacity() >= 10);
921    }
922
923    #[test]
924    fn test_other_reserve() {
925        let mut buf = [1, 1, 4, 5, 1, 4];
926        let res = IoBufMut::reserve(&mut buf, 10);
927        assert!(res.is_err_and(|x| x.is_not_supported()));
928        assert!(buf.buf_capacity() == 6);
929    }
930
931    #[test]
932    fn test_extend() {
933        let mut buf = Vec::from(b"hello");
934        IoBufMut::extend_from_slice(&mut buf, b" world").unwrap();
935        assert_eq!(buf.as_slice(), b"hello world");
936
937        let mut buf = [];
938        let res = IoBufMut::extend_from_slice(&mut buf, b" ");
939        assert!(res.is_err_and(|x| x.is_not_supported()));
940    }
941}