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#[cfg(feature = "memmap2")]
198impl IoBuf for memmap2::Mmap {
199    fn as_init(&self) -> &[u8] {
200        self
201    }
202}
203
204#[cfg(feature = "memmap2")]
205impl IoBuf for memmap2::MmapMut {
206    fn as_init(&self) -> &[u8] {
207        self
208    }
209}
210
211/// An error indicating that reserving capacity for a buffer failed.
212#[must_use]
213#[derive(Debug)]
214pub enum ReserveError {
215    /// Reservation is not supported.
216    NotSupported,
217
218    /// Reservation failed.
219    ///
220    /// This is usually caused by out-of-memory.
221    ReserveFailed(Box<dyn Error + Send + Sync>),
222}
223
224impl ReserveError {
225    /// Check if the error is [`NotSupported`].
226    ///
227    /// [`NotSupported`]: ReserveError::NotSupported
228    pub fn is_not_supported(&self) -> bool {
229        matches!(self, ReserveError::NotSupported)
230    }
231}
232
233impl Display for ReserveError {
234    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
235        match self {
236            ReserveError::NotSupported => write!(f, "reservation is not supported"),
237            ReserveError::ReserveFailed(src) => write!(f, "reservation failed: {src}"),
238        }
239    }
240}
241
242impl Error for ReserveError {
243    fn source(&self) -> Option<&(dyn Error + 'static)> {
244        match self {
245            ReserveError::ReserveFailed(src) => Some(src.as_ref()),
246            _ => None,
247        }
248    }
249}
250
251impl From<ReserveError> for std::io::Error {
252    fn from(value: ReserveError) -> Self {
253        match value {
254            ReserveError::NotSupported => {
255                std::io::Error::new(std::io::ErrorKind::Unsupported, "reservation not supported")
256            }
257            ReserveError::ReserveFailed(src) => {
258                std::io::Error::new(std::io::ErrorKind::OutOfMemory, src)
259            }
260        }
261    }
262}
263
264/// An error indicating that reserving exact capacity for a buffer failed.
265#[must_use]
266#[derive(Debug)]
267pub enum ReserveExactError {
268    /// Reservation is not supported.
269    NotSupported,
270
271    /// Reservation failed.
272    ///
273    /// This is usually caused by out-of-memory.
274    ReserveFailed(Box<dyn Error + Send + Sync>),
275
276    /// Reserved size does not match the expected size.
277    ExactSizeMismatch {
278        /// Expected size to reserve
279        expected: usize,
280
281        /// Actual size reserved
282        reserved: usize,
283    },
284}
285
286impl ReserveExactError {
287    /// Check if the error is [`NotSupported`]
288    ///
289    /// [`NotSupported`]: ReserveExactError::NotSupported
290    pub fn is_not_supported(&self) -> bool {
291        matches!(self, ReserveExactError::NotSupported)
292    }
293}
294
295impl Display for ReserveExactError {
296    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
297        match self {
298            ReserveExactError::NotSupported => write!(f, "reservation is not supported"),
299            ReserveExactError::ReserveFailed(src) => write!(f, "reservation failed: {src}"),
300            ReserveExactError::ExactSizeMismatch { reserved, expected } => {
301                write!(
302                    f,
303                    "reserved size mismatch: expected {}, reserved {}",
304                    expected, reserved
305                )
306            }
307        }
308    }
309}
310
311impl From<ReserveError> for ReserveExactError {
312    fn from(err: ReserveError) -> Self {
313        match err {
314            ReserveError::NotSupported => ReserveExactError::NotSupported,
315            ReserveError::ReserveFailed(src) => ReserveExactError::ReserveFailed(src),
316        }
317    }
318}
319
320impl Error for ReserveExactError {
321    fn source(&self) -> Option<&(dyn Error + 'static)> {
322        match self {
323            ReserveExactError::ReserveFailed(src) => Some(src.as_ref()),
324            _ => None,
325        }
326    }
327}
328
329impl From<ReserveExactError> for std::io::Error {
330    fn from(value: ReserveExactError) -> Self {
331        match value {
332            ReserveExactError::NotSupported => {
333                std::io::Error::new(std::io::ErrorKind::Unsupported, "reservation not supported")
334            }
335            ReserveExactError::ReserveFailed(src) => {
336                std::io::Error::new(std::io::ErrorKind::OutOfMemory, src)
337            }
338            ReserveExactError::ExactSizeMismatch { expected, reserved } => std::io::Error::other(
339                format!("reserved size mismatch: expected {expected}, reserved {reserved}",),
340            ),
341        }
342    }
343}
344
345#[cfg(feature = "smallvec")]
346mod smallvec_err {
347    use std::{error::Error, fmt::Display};
348
349    use smallvec::CollectionAllocErr;
350
351    #[derive(Debug)]
352    pub(super) struct SmallVecErr(pub CollectionAllocErr);
353
354    impl Display for SmallVecErr {
355        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
356            write!(f, "SmallVec allocation error: {}", self.0)
357        }
358    }
359
360    impl Error for SmallVecErr {}
361}
362
363/// A trait for mutable buffers.
364///
365/// The `IoBufMut` trait is implemented by buffer types that can be passed to
366/// mutable completion-based IO operations, like reading content from a file and
367/// write to the buffer. This trait will take all space of a buffer into
368/// account, including uninitialized bytes.
369pub trait IoBufMut: IoBuf + SetLen {
370    /// Get the full mutable slice of the buffer, including both initialized
371    /// and uninitialized bytes.
372    fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>];
373
374    /// Initialize all bytes in the buffer and return them.
375    ///
376    /// Bytes in the already-initialized prefix (`0..buf_len()`) are preserved.
377    /// Only the uninitialized tail (`buf_len()..buf_capacity()`) is
378    /// zero-initialized.
379    fn ensure_init(&mut self) -> &mut [u8] {
380        let len = (*self).buf_len();
381        let slice = self.as_uninit();
382        slice[len..].fill(MaybeUninit::new(0));
383        unsafe { slice.assume_init_mut() }
384    }
385
386    /// Total capacity of the buffer, including both initialized and
387    /// uninitialized bytes.
388    fn buf_capacity(&mut self) -> usize {
389        self.as_uninit().len()
390    }
391
392    /// Get the raw mutable pointer to the buffer.
393    fn buf_mut_ptr(&mut self) -> *mut MaybeUninit<u8> {
394        self.as_uninit().as_mut_ptr()
395    }
396
397    /// Get the mutable slice of initialized bytes. The content is the same as
398    /// [`IoBuf::as_init`], but mutable.
399    fn as_mut_slice(&mut self) -> &mut [u8] {
400        let len = (*self).buf_len();
401        let ptr = (*self).buf_mut_ptr();
402        // SAFETY:
403        // - lifetime of the returned slice is bounded by &mut self
404        // - bytes within `len` are guaranteed to be initialized
405        // - the pointer is derived from
406        unsafe { std::slice::from_raw_parts_mut(ptr as *mut u8, len) }
407    }
408
409    /// Extend the buffer by copying bytes from `src`.
410    ///
411    /// The buffer will reserve additional capacity if necessary, and return an
412    /// error when reservation failed.
413    ///
414    /// Notice that this may move the memory of the buffer, so it's UB to
415    /// call this after the buffer is being pinned.
416    // FIXME: Change to `slice::write_copy_of_slice` when stabilized
417    fn extend_from_slice(&mut self, src: &[u8]) -> Result<(), ReserveError> {
418        let len = src.len();
419        let init = (*self).buf_len();
420        self.reserve(len)?;
421        let ptr = self.buf_mut_ptr().wrapping_add(init);
422
423        unsafe {
424            // SAFETY:
425            // - we have reserved enough capacity so the ptr and len stays in one allocation
426            // - src is valid for len bytes
427            // - ptr is valid for len bytes
428            // - &mut self guarantees that src cannot overlap with dst
429            std::ptr::copy_nonoverlapping(src.as_ptr() as _, ptr, len);
430
431            // SAFETY: the bytes in range [init, init + len) are initialized now
432            self.advance_to(init + len);
433        }
434
435        Ok(())
436    }
437
438    /// Like [`slice::copy_within`], copy a range of bytes within the buffer to
439    /// another location in the same buffer. This will count in both initialized
440    /// and uninitialized bytes.
441    ///
442    /// # Panics
443    ///
444    /// This method will panic if the source or destination range is out of
445    /// bounds.
446    ///
447    /// [`slice::copy_within`]: https://doc.rust-lang.org/std/primitive.slice.html#method.copy_within
448    fn copy_within<R>(&mut self, src: R, dest: usize)
449    where
450        R: RangeBounds<usize>,
451    {
452        self.as_uninit().copy_within(src, dest);
453    }
454
455    /// Reserve additional capacity for the buffer.
456    ///
457    /// By default, this checks if the spare capacity is enough to fit in
458    /// `len`-bytes. If it does, returns `Ok(())`, and otherwise returns
459    /// [`Err(ReserveError::NotSupported)`]. Types that support dynamic
460    /// resizing (like `Vec<u8>`) will override this method to actually
461    /// reserve capacity. The return value indicates whether the reservation
462    /// succeeded. See [`ReserveError`] for details.
463    ///
464    /// Notice that this may move the memory of the buffer, so it's UB to
465    /// call this after the buffer is being pinned.
466    ///
467    /// [`Err(ReserveError::NotSupported)`]: ReserveError::NotSupported
468    fn reserve(&mut self, len: usize) -> Result<(), ReserveError> {
469        let init = (*self).buf_len();
470        if len <= self.buf_capacity() - init {
471            return Ok(());
472        }
473        Err(ReserveError::NotSupported)
474    }
475
476    /// Reserve exactly `len` additional capacity for the buffer.
477    ///
478    /// By default this falls back to [`IoBufMut::reserve`]. Types that support
479    /// dynamic resizing (like `Vec<u8>`) will override this method to
480    /// actually reserve capacity. The return value indicates whether the
481    /// exact reservation succeeded. See [`ReserveExactError`] for details.
482    ///
483    /// Notice that this may move the memory of the buffer, so it's UB to
484    /// call this after the buffer is being pinned.
485    fn reserve_exact(&mut self, len: usize) -> Result<(), ReserveExactError> {
486        self.reserve(len)?;
487        Ok(())
488    }
489
490    /// Returns an [`Uninit`], which is a [`Slice`] that only exposes
491    /// uninitialized bytes.
492    ///
493    /// It will always point to the uninitialized area of a [`IoBufMut`] even
494    /// after reading in some bytes, which is done by [`SetLen`]. This
495    /// is useful for writing data into buffer without overwriting any
496    /// existing bytes.
497    ///
498    /// # Examples
499    ///
500    /// ```
501    /// use compio_buf::{IoBuf, IoBufMut};
502    ///
503    /// let mut buf = Vec::from(b"hello world");
504    /// buf.reserve_exact(10);
505    /// let mut slice = buf.uninit();
506    ///
507    /// assert_eq!(slice.as_init(), b"");
508    /// assert_eq!(slice.buf_capacity(), 10);
509    /// ```
510    fn uninit(self) -> Uninit<Self>
511    where
512        Self: Sized,
513    {
514        Uninit::new(self)
515    }
516
517    /// Create a [`Writer`] from this buffer, which implements
518    /// [`std::io::Write`].
519    fn into_writer(self) -> Writer<Self>
520    where
521        Self: Sized,
522    {
523        Writer::new(self)
524    }
525
526    /// Create a [`Writer`] from a mutable reference of the buffer, which
527    /// implements [`std::io::Write`].
528    fn as_writer(&mut self) -> WriterRef<'_, Self> {
529        WriterRef::new(self)
530    }
531
532    /// Indicate whether the buffer has been filled (uninit portion is empty)
533    fn is_filled(&mut self) -> bool {
534        let len = (*self).as_init().len();
535        let cap = (*self).buf_capacity();
536        len == cap
537    }
538}
539
540impl<B: IoBufMut + ?Sized> IoBufMut for &'static mut B {
541    fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
542        (**self).as_uninit()
543    }
544
545    fn reserve(&mut self, len: usize) -> Result<(), ReserveError> {
546        (**self).reserve(len)
547    }
548
549    fn reserve_exact(&mut self, len: usize) -> Result<(), ReserveExactError> {
550        (**self).reserve_exact(len)
551    }
552}
553
554impl<B: IoBufMut + ?Sized, #[cfg(feature = "allocator_api")] A: Allocator + 'static> IoBufMut
555    for t_alloc!(Box, B, A)
556{
557    fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
558        (**self).as_uninit()
559    }
560
561    fn reserve(&mut self, len: usize) -> Result<(), ReserveError> {
562        (**self).reserve(len)
563    }
564
565    fn reserve_exact(&mut self, len: usize) -> Result<(), ReserveExactError> {
566        (**self).reserve_exact(len)
567    }
568}
569
570impl<#[cfg(feature = "allocator_api")] A: Allocator + 'static> IoBufMut for t_alloc!(Vec, u8, A) {
571    fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
572        let ptr = self.as_mut_ptr() as *mut MaybeUninit<u8>;
573        let cap = self.capacity();
574        // SAFETY: Vec guarantees that the pointer is valid for `capacity` bytes
575        unsafe { std::slice::from_raw_parts_mut(ptr, cap) }
576    }
577
578    fn reserve(&mut self, len: usize) -> Result<(), ReserveError> {
579        if let Err(e) = Vec::try_reserve(self, len) {
580            return Err(ReserveError::ReserveFailed(Box::new(e)));
581        }
582
583        Ok(())
584    }
585
586    fn reserve_exact(&mut self, len: usize) -> Result<(), ReserveExactError> {
587        if self.capacity() - self.len() >= len {
588            return Ok(());
589        }
590
591        if let Err(e) = Vec::try_reserve_exact(self, len) {
592            return Err(ReserveExactError::ReserveFailed(Box::new(e)));
593        }
594
595        if self.capacity() - self.len() != len {
596            return Err(ReserveExactError::ExactSizeMismatch {
597                reserved: self.capacity() - self.len(),
598                expected: len,
599            });
600        }
601        Ok(())
602    }
603}
604
605impl IoBufMut for [u8] {
606    fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
607        let ptr = self.as_mut_ptr() as *mut MaybeUninit<u8>;
608        let len = self.len();
609        // SAFETY: slice is fully initialized, so treating it as MaybeUninit is safe
610        unsafe { std::slice::from_raw_parts_mut(ptr, len) }
611    }
612}
613
614impl<const N: usize> IoBufMut for [u8; N] {
615    fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
616        let ptr = self.as_mut_ptr() as *mut MaybeUninit<u8>;
617        // SAFETY: array is fully initialized, so treating it as MaybeUninit is safe
618        unsafe { std::slice::from_raw_parts_mut(ptr, N) }
619    }
620}
621
622#[cfg(feature = "bytes")]
623impl IoBufMut for bytes::BytesMut {
624    fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
625        let ptr = self.as_mut_ptr() as *mut MaybeUninit<u8>;
626        let cap = self.capacity();
627        // SAFETY: BytesMut guarantees that the pointer is valid for `capacity` bytes
628        unsafe { std::slice::from_raw_parts_mut(ptr, cap) }
629    }
630
631    fn reserve(&mut self, len: usize) -> Result<(), ReserveError> {
632        bytes::BytesMut::reserve(self, len);
633        Ok(())
634    }
635
636    fn reserve_exact(&mut self, len: usize) -> Result<(), ReserveExactError> {
637        if self.capacity() - self.len() >= len {
638            return Ok(());
639        }
640
641        bytes::BytesMut::reserve(self, len);
642
643        if self.capacity() - self.len() != len {
644            Err(ReserveExactError::ExactSizeMismatch {
645                reserved: self.capacity() - self.len(),
646                expected: len,
647            })
648        } else {
649            Ok(())
650        }
651    }
652}
653
654#[cfg(feature = "read_buf")]
655impl IoBufMut for std::io::BorrowedBuf<'static> {
656    fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
657        let total_cap = self.capacity();
658
659        // SAFETY: We reconstruct the full buffer from the filled portion pointer.
660        // BorrowedBuf guarantees that the underlying buffer has capacity bytes.
661        unsafe {
662            let filled_ptr = self.filled().as_ptr() as *mut MaybeUninit<u8>;
663            std::slice::from_raw_parts_mut(filled_ptr, total_cap)
664        }
665    }
666}
667
668#[cfg(feature = "arrayvec")]
669impl<const N: usize> IoBufMut for arrayvec::ArrayVec<u8, N> {
670    fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
671        let ptr = self.as_mut_ptr() as *mut MaybeUninit<u8>;
672        // SAFETY: ArrayVec guarantees that the pointer is valid for N bytes
673        unsafe { std::slice::from_raw_parts_mut(ptr, N) }
674    }
675}
676
677#[cfg(feature = "smallvec")]
678impl<const N: usize> IoBufMut for smallvec::SmallVec<[u8; N]>
679where
680    [u8; N]: smallvec::Array<Item = u8>,
681{
682    fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
683        let ptr = self.as_mut_ptr() as *mut MaybeUninit<u8>;
684        let cap = self.capacity();
685        // SAFETY: SmallVec guarantees that the pointer is valid for `capacity` bytes
686        unsafe { std::slice::from_raw_parts_mut(ptr, cap) }
687    }
688
689    fn reserve(&mut self, len: usize) -> Result<(), ReserveError> {
690        if let Err(e) = smallvec::SmallVec::try_reserve(self, len) {
691            return Err(ReserveError::ReserveFailed(Box::new(
692                smallvec_err::SmallVecErr(e),
693            )));
694        }
695        Ok(())
696    }
697
698    fn reserve_exact(&mut self, len: usize) -> Result<(), ReserveExactError> {
699        if self.capacity() - self.len() >= len {
700            return Ok(());
701        }
702
703        if let Err(e) = smallvec::SmallVec::try_reserve_exact(self, len) {
704            return Err(ReserveExactError::ReserveFailed(Box::new(
705                smallvec_err::SmallVecErr(e),
706            )));
707        }
708
709        if self.capacity() - self.len() != len {
710            return Err(ReserveExactError::ExactSizeMismatch {
711                reserved: self.capacity() - self.len(),
712                expected: len,
713            });
714        }
715        Ok(())
716    }
717}
718
719#[cfg(feature = "memmap2")]
720impl IoBufMut for memmap2::MmapMut {
721    fn as_uninit(&mut self) -> &mut [MaybeUninit<u8>] {
722        // Safety: &mut [u8] is valid &mut [MaybeUninit<u8>]
723        unsafe { std::mem::transmute(self.as_mut_slice()) }
724    }
725}
726
727/// A helper trait for `set_len` like methods.
728pub trait SetLen {
729    /// Set the buffer length.
730    ///
731    /// # Safety
732    ///
733    /// * `len` must be less or equal than `as_uninit().len()`.
734    /// * The bytes in the range `[buf_len(), len)` must be initialized.
735    unsafe fn set_len(&mut self, len: usize);
736
737    /// Advance the buffer length by `len`.
738    ///
739    /// # Safety
740    ///
741    /// * The bytes in the range `[buf_len(), buf_len() + len)` must be
742    ///   initialized.
743    unsafe fn advance(&mut self, len: usize)
744    where
745        Self: IoBuf,
746    {
747        let current_len = (*self).buf_len();
748        let new_len = current_len.checked_add(len).expect("length overflow");
749        unsafe { self.set_len(new_len) };
750    }
751
752    /// Set the buffer length to `len`. If `len` is less than the current
753    /// length, this operation is a no-op.
754    ///
755    /// # Safety
756    ///
757    /// * `len` must be less or equal than `as_uninit().len()`.
758    /// * The bytes in the range `[buf_len(), len)` must be initialized.
759    unsafe fn advance_to(&mut self, len: usize)
760    where
761        Self: IoBuf,
762    {
763        let current_len = (*self).buf_len();
764        if len > current_len {
765            unsafe { self.set_len(len) };
766        }
767    }
768
769    /// Set the vector buffer's total length to `len`. If `len` is less than the
770    /// current total length, this operation is a no-op.
771    ///
772    /// # Safety
773    ///
774    /// * `len` must be less or equal than `total_len()`.
775    /// * The bytes in the range `[total_len(), len)` must be initialized.
776    unsafe fn advance_vec_to(&mut self, len: usize)
777    where
778        Self: IoVectoredBuf,
779    {
780        let current_len = (*self).total_len();
781        if len > current_len {
782            unsafe { self.set_len(len) };
783        }
784    }
785
786    /// Clear the buffer, setting its length to 0 without touching its content
787    /// or capacity.
788    fn clear(&mut self)
789    where
790        Self: IoBuf,
791    {
792        // SAFETY: setting length to 0 is always valid
793        unsafe { self.set_len(0) };
794    }
795}
796
797impl<B: SetLen + ?Sized> SetLen for &'static mut B {
798    unsafe fn set_len(&mut self, len: usize) {
799        unsafe { (**self).set_len(len) }
800    }
801}
802
803impl<B: SetLen + ?Sized, #[cfg(feature = "allocator_api")] A: Allocator + 'static> SetLen
804    for t_alloc!(Box, B, A)
805{
806    unsafe fn set_len(&mut self, len: usize) {
807        unsafe { (**self).set_len(len) }
808    }
809}
810
811impl<#[cfg(feature = "allocator_api")] A: Allocator + 'static> SetLen for t_alloc!(Vec, u8, A) {
812    unsafe fn set_len(&mut self, len: usize) {
813        unsafe { self.set_len(len) };
814    }
815}
816
817impl SetLen for [u8] {
818    unsafe fn set_len(&mut self, len: usize) {
819        debug_assert!(len <= self.len());
820    }
821}
822
823impl<const N: usize> SetLen for [u8; N] {
824    unsafe fn set_len(&mut self, len: usize) {
825        debug_assert!(len <= N);
826    }
827}
828
829#[cfg(feature = "bytes")]
830impl SetLen for bytes::BytesMut {
831    unsafe fn set_len(&mut self, len: usize) {
832        unsafe { self.set_len(len) };
833    }
834}
835
836#[cfg(feature = "read_buf")]
837impl SetLen for std::io::BorrowedBuf<'static> {
838    unsafe fn set_len(&mut self, len: usize) {
839        debug_assert!(self.capacity() >= len);
840
841        // SAFETY: `len` range is initialized guaranteed by invariant of `set_len`
842        #[allow(unused_unsafe)]
843        unsafe {
844            self.clear().unfilled().advance(len)
845        };
846    }
847}
848
849#[cfg(feature = "arrayvec")]
850impl<const N: usize> SetLen for arrayvec::ArrayVec<u8, N> {
851    unsafe fn set_len(&mut self, len: usize) {
852        if (**self).buf_len() < len {
853            unsafe { self.set_len(len) };
854        }
855    }
856}
857
858#[cfg(feature = "smallvec")]
859impl<const N: usize> SetLen for smallvec::SmallVec<[u8; N]>
860where
861    [u8; N]: smallvec::Array<Item = u8>,
862{
863    unsafe fn set_len(&mut self, len: usize) {
864        if (**self).buf_len() < len {
865            unsafe { self.set_len(len) };
866        }
867    }
868}
869
870#[cfg(feature = "memmap2")]
871impl SetLen for memmap2::MmapMut {
872    unsafe fn set_len(&mut self, len: usize) {
873        debug_assert!(len <= self.len())
874    }
875}
876
877impl<T: IoBufMut> SetLen for [T] {
878    unsafe fn set_len(&mut self, len: usize) {
879        unsafe { default_set_len(self.iter_mut(), len) }
880    }
881}
882
883impl<T: IoBufMut, const N: usize> SetLen for [T; N] {
884    unsafe fn set_len(&mut self, len: usize) {
885        unsafe { default_set_len(self.iter_mut(), len) }
886    }
887}
888
889impl<T: IoBufMut, #[cfg(feature = "allocator_api")] A: Allocator + 'static> SetLen
890    for t_alloc!(Vec, T, A)
891{
892    unsafe fn set_len(&mut self, len: usize) {
893        unsafe { default_set_len(self.iter_mut(), len) }
894    }
895}
896
897#[cfg(feature = "arrayvec")]
898impl<T: IoBufMut, const N: usize> SetLen for arrayvec::ArrayVec<T, N> {
899    unsafe fn set_len(&mut self, len: usize) {
900        unsafe { default_set_len(self.iter_mut(), len) }
901    }
902}
903
904#[cfg(feature = "smallvec")]
905impl<T: IoBufMut, const N: usize> SetLen for smallvec::SmallVec<[T; N]>
906where
907    [T; N]: smallvec::Array<Item = T>,
908{
909    unsafe fn set_len(&mut self, len: usize) {
910        unsafe { default_set_len(self.iter_mut(), len) }
911    }
912}
913
914/// # Safety
915/// * `len` should be less or equal than the sum of `buf_capacity()` of all
916///   buffers.
917/// * The bytes in the range `[buf_len(), new_len)` of each buffer must be
918///   initialized
919unsafe fn default_set_len<'a, B: IoBufMut>(
920    iter: impl IntoIterator<Item = &'a mut B>,
921    mut len: usize,
922) {
923    let mut iter = iter.into_iter();
924    while len > 0 {
925        let Some(curr) = iter.next() else { return };
926        let sub = (*curr).buf_capacity().min(len);
927        unsafe { curr.set_len(sub) };
928        len -= sub;
929    }
930}
931
932#[cfg(test)]
933mod test {
934    use crate::IoBufMut;
935
936    #[test]
937    fn test_vec_reserve() {
938        let mut buf = Vec::new();
939        IoBufMut::reserve(&mut buf, 10).unwrap();
940        assert!(buf.capacity() >= 10);
941
942        let mut buf = Vec::new();
943        IoBufMut::reserve_exact(&mut buf, 10).unwrap();
944        assert!(buf.capacity() == 10);
945
946        let mut buf = Box::new(Vec::new());
947        IoBufMut::reserve_exact(&mut buf, 10).unwrap();
948        assert!(buf.capacity() == 10);
949    }
950
951    #[test]
952    #[cfg(feature = "bytes")]
953    fn test_bytes_reserve() {
954        let mut buf = bytes::BytesMut::new();
955        IoBufMut::reserve(&mut buf, 10).unwrap();
956        assert!(buf.capacity() >= 10);
957    }
958
959    #[test]
960    #[cfg(feature = "smallvec")]
961    fn test_smallvec_reserve() {
962        let mut buf = smallvec::SmallVec::<[u8; 8]>::new();
963        IoBufMut::reserve(&mut buf, 10).unwrap();
964        assert!(buf.capacity() >= 10);
965    }
966
967    #[test]
968    #[cfg(feature = "memmap2")]
969    fn tests_memmap2() {
970        use std::{
971            fs::{OpenOptions, remove_file},
972            io::{Seek, SeekFrom, Write},
973        };
974
975        use memmap2::MmapOptions;
976
977        use super::*;
978
979        let path = std::env::temp_dir().join("compio_buf_mmap_mut_test");
980
981        let mut file = OpenOptions::new()
982            .read(true)
983            .write(true)
984            .create(true)
985            .truncate(true)
986            .open(&path)
987            .unwrap();
988        let data = b"hello memmap2";
989        file.write_all(data).unwrap();
990        file.flush().unwrap();
991        file.seek(SeekFrom::Start(0)).unwrap();
992        let mmap = unsafe { MmapOptions::new().map(&file).unwrap() };
993
994        let uninit_slice = mmap.as_init();
995        assert_eq!(uninit_slice, data);
996
997        remove_file(path).unwrap();
998    }
999
1000    #[test]
1001    fn test_other_reserve() {
1002        let mut buf = [1, 1, 4, 5, 1, 4];
1003        let res = IoBufMut::reserve(&mut buf, 10);
1004        assert!(res.is_err_and(|x| x.is_not_supported()));
1005        assert!(buf.buf_capacity() == 6);
1006    }
1007
1008    #[test]
1009    fn test_extend() {
1010        let mut buf = Vec::from(b"hello");
1011        IoBufMut::extend_from_slice(&mut buf, b" world").unwrap();
1012        assert_eq!(buf.as_slice(), b"hello world");
1013
1014        let mut buf = [];
1015        let res = IoBufMut::extend_from_slice(&mut buf, b" ");
1016        assert!(res.is_err_and(|x| x.is_not_supported()));
1017    }
1018}