Skip to main content

commonware_runtime/iobuf/
bufs.rs

1//! Immutable and mutable collections of I/O buffers.
2//!
3//! [`IoBufs`] and [`IoBufsMut`] present multiple buffers as one logical byte
4//! stream. [`Builder`] assembles an [`IoBufs`] from encoded bytes and existing
5//! byte segments, and [`EncodeExt`] provides pool-backed encoding helpers.
6
7use super::{
8    buf::{IoBuf, IoBufMut},
9    panic_advance,
10    pool::BufferPool,
11};
12use bytes::{Buf, BufMut, Bytes, BytesMut};
13use commonware_codec::{BufsMut, EncodeSize, Write};
14use std::{collections::VecDeque, io::IoSlice, num::NonZeroUsize};
15
16/// Container for one or more immutable buffers.
17#[derive(Clone, Debug)]
18pub struct IoBufs {
19    inner: IoBufsInner,
20}
21
22/// Internal immutable representation.
23///
24/// - Representation is canonical and minimal for readable data:
25///   - `Single` is the only representation for empty data and one-chunk data.
26///   - `Chunked` is used only when four or more readable chunks remain.
27/// - `Pair`, `Triple`, and `Chunked` never store empty chunks.
28#[derive(Clone, Debug)]
29enum IoBufsInner {
30    /// Single buffer (fast path).
31    Single(IoBuf),
32    /// Two buffers (fast path).
33    Pair([IoBuf; 2]),
34    /// Three buffers (fast path).
35    Triple([IoBuf; 3]),
36    /// Four or more buffers.
37    Chunked(VecDeque<IoBuf>),
38}
39
40impl Default for IoBufs {
41    fn default() -> Self {
42        Self {
43            inner: IoBufsInner::Single(IoBuf::default()),
44        }
45    }
46}
47
48impl IoBufs {
49    /// Build canonical immutable chunk storage from readable chunks.
50    ///
51    /// Empty chunks are removed before representation selection.
52    fn from_chunks_iter(chunks: impl IntoIterator<Item = IoBuf>) -> Self {
53        let mut iter = chunks.into_iter().filter(|buf| !buf.is_empty());
54        let first = match iter.next() {
55            Some(first) => first,
56            None => return Self::default(),
57        };
58        let second = match iter.next() {
59            Some(second) => second,
60            None => {
61                return Self {
62                    inner: IoBufsInner::Single(first),
63                };
64            }
65        };
66        let third = match iter.next() {
67            Some(third) => third,
68            None => {
69                return Self {
70                    inner: IoBufsInner::Pair([first, second]),
71                };
72            }
73        };
74        let fourth = match iter.next() {
75            Some(fourth) => fourth,
76            None => {
77                return Self {
78                    inner: IoBufsInner::Triple([first, second, third]),
79                };
80            }
81        };
82
83        let mut bufs = VecDeque::with_capacity(4);
84        bufs.push_back(first);
85        bufs.push_back(second);
86        bufs.push_back(third);
87        bufs.push_back(fourth);
88        bufs.extend(iter);
89
90        Self {
91            inner: IoBufsInner::Chunked(bufs),
92        }
93    }
94
95    /// Re-establish canonical immutable representation invariants.
96    fn canonicalize(&mut self) {
97        let inner = std::mem::replace(&mut self.inner, IoBufsInner::Single(IoBuf::default()));
98        self.inner = match inner {
99            IoBufsInner::Single(buf) => {
100                if buf.is_empty() {
101                    IoBufsInner::Single(IoBuf::default())
102                } else {
103                    IoBufsInner::Single(buf)
104                }
105            }
106            IoBufsInner::Pair([a, b]) => Self::from_chunks_iter([a, b]).inner,
107            IoBufsInner::Triple([a, b, c]) => Self::from_chunks_iter([a, b, c]).inner,
108            IoBufsInner::Chunked(bufs) => Self::from_chunks_iter(bufs).inner,
109        };
110    }
111
112    /// Returns a reference to the single contiguous buffer, if present.
113    ///
114    /// Returns `Some` only when all remaining data is in one contiguous buffer.
115    pub const fn as_single(&self) -> Option<&IoBuf> {
116        match &self.inner {
117            IoBufsInner::Single(buf) => Some(buf),
118            _ => None,
119        }
120    }
121
122    /// Consume this container and return the single buffer if present.
123    ///
124    /// Returns `Ok(IoBuf)` only when all remaining data is already contained in
125    /// a single chunk. Returns `Err(Self)` with the original container
126    /// otherwise.
127    pub fn try_into_single(self) -> Result<IoBuf, Self> {
128        match self.inner {
129            IoBufsInner::Single(buf) => Ok(buf),
130            inner => Err(Self { inner }),
131        }
132    }
133
134    /// Number of bytes remaining across all buffers.
135    #[inline]
136    pub fn len(&self) -> usize {
137        self.remaining()
138    }
139
140    /// Number of non-empty readable chunks.
141    #[inline]
142    pub fn chunk_count(&self) -> usize {
143        // This assumes canonical form.
144        match &self.inner {
145            IoBufsInner::Single(buf) => {
146                if buf.is_empty() {
147                    0
148                } else {
149                    1
150                }
151            }
152            IoBufsInner::Pair(_) => 2,
153            IoBufsInner::Triple(_) => 3,
154            IoBufsInner::Chunked(bufs) => bufs.len(),
155        }
156    }
157
158    /// Whether all buffers are empty.
159    #[inline]
160    pub fn is_empty(&self) -> bool {
161        self.remaining() == 0
162    }
163
164    /// Whether this contains a single contiguous buffer.
165    ///
166    /// When true, `chunk()` returns all remaining bytes.
167    #[inline]
168    pub const fn is_single(&self) -> bool {
169        matches!(self.inner, IoBufsInner::Single(_))
170    }
171
172    /// Visit each readable chunk in order without coalescing.
173    #[inline]
174    pub fn for_each_chunk(&self, mut f: impl FnMut(&[u8])) {
175        match &self.inner {
176            IoBufsInner::Single(buf) => {
177                let chunk = buf.as_ref();
178                if !chunk.is_empty() {
179                    f(chunk);
180                }
181            }
182            IoBufsInner::Pair(pair) => {
183                for buf in pair {
184                    let chunk = buf.as_ref();
185                    if !chunk.is_empty() {
186                        f(chunk);
187                    }
188                }
189            }
190            IoBufsInner::Triple(triple) => {
191                for buf in triple {
192                    let chunk = buf.as_ref();
193                    if !chunk.is_empty() {
194                        f(chunk);
195                    }
196                }
197            }
198            IoBufsInner::Chunked(bufs) => {
199                for buf in bufs {
200                    let chunk = buf.as_ref();
201                    if !chunk.is_empty() {
202                        f(chunk);
203                    }
204                }
205            }
206        }
207    }
208
209    /// Prepend a buffer to the front.
210    ///
211    /// Empty input buffers are ignored.
212    pub fn prepend(&mut self, buf: IoBuf) {
213        if buf.is_empty() {
214            return;
215        }
216        let inner = std::mem::replace(&mut self.inner, IoBufsInner::Single(IoBuf::default()));
217        self.inner = match inner {
218            IoBufsInner::Single(existing) if existing.is_empty() => IoBufsInner::Single(buf),
219            IoBufsInner::Single(existing) => IoBufsInner::Pair([buf, existing]),
220            IoBufsInner::Pair([a, b]) => IoBufsInner::Triple([buf, a, b]),
221            IoBufsInner::Triple([a, b, c]) => {
222                let mut bufs = VecDeque::with_capacity(4);
223                bufs.push_back(buf);
224                bufs.push_back(a);
225                bufs.push_back(b);
226                bufs.push_back(c);
227                IoBufsInner::Chunked(bufs)
228            }
229            IoBufsInner::Chunked(mut bufs) => {
230                bufs.push_front(buf);
231                IoBufsInner::Chunked(bufs)
232            }
233        };
234    }
235
236    /// Append a buffer to the back.
237    ///
238    /// Empty input buffers are ignored.
239    pub fn append(&mut self, buf: IoBuf) {
240        if buf.is_empty() {
241            return;
242        }
243        let inner = std::mem::replace(&mut self.inner, IoBufsInner::Single(IoBuf::default()));
244        self.inner = match inner {
245            IoBufsInner::Single(existing) if existing.is_empty() => IoBufsInner::Single(buf),
246            IoBufsInner::Single(existing) => IoBufsInner::Pair([existing, buf]),
247            IoBufsInner::Pair([a, b]) => IoBufsInner::Triple([a, b, buf]),
248            IoBufsInner::Triple([a, b, c]) => {
249                let mut bufs = VecDeque::with_capacity(4);
250                bufs.push_back(a);
251                bufs.push_back(b);
252                bufs.push_back(c);
253                bufs.push_back(buf);
254                IoBufsInner::Chunked(bufs)
255            }
256            IoBufsInner::Chunked(mut bufs) => {
257                bufs.push_back(buf);
258                IoBufsInner::Chunked(bufs)
259            }
260        };
261    }
262
263    /// Splits the buffer(s) into two at the given index.
264    ///
265    /// Afterwards `self` contains bytes `[at, len)`, and the returned
266    /// [`IoBufs`] contains bytes `[0, at)`.
267    ///
268    /// Whole chunks are moved without copying. If the split point lands inside
269    /// a chunk, the chunk is split zero-copy via [`IoBuf::split_to`].
270    ///
271    /// # Panics
272    ///
273    /// Panics if `at > len`.
274    pub fn split_to(&mut self, at: usize) -> Self {
275        if at == 0 {
276            return Self::default();
277        }
278
279        let remaining = self.remaining();
280        assert!(
281            at <= remaining,
282            "split_to out of bounds: {:?} <= {:?}",
283            at,
284            remaining,
285        );
286
287        if at == remaining {
288            return std::mem::take(self);
289        }
290
291        let inner = std::mem::replace(&mut self.inner, IoBufsInner::Single(IoBuf::default()));
292        match inner {
293            IoBufsInner::Single(mut buf) => {
294                // Delegate directly and keep remainder as single
295                let prefix = buf.split_to(at);
296                self.inner = IoBufsInner::Single(buf);
297                Self::from(prefix)
298            }
299            IoBufsInner::Pair([mut a, mut b]) => {
300                let a_len = a.remaining();
301                if at < a_len {
302                    // Split stays entirely in chunk `a`.
303                    let prefix = a.split_to(at);
304                    self.inner = IoBufsInner::Pair([a, b]);
305                    return Self::from(prefix);
306                }
307                if at == a_len {
308                    // Exact chunk boundary: move `a` out, keep `b`.
309                    self.inner = IoBufsInner::Single(b);
310                    return Self::from(a);
311                }
312
313                // Split crosses from `a` into `b`.
314                let b_prefix_len = at - a_len;
315                let b_prefix = b.split_to(b_prefix_len);
316                self.inner = IoBufsInner::Single(b);
317                Self {
318                    inner: IoBufsInner::Pair([a, b_prefix]),
319                }
320            }
321            IoBufsInner::Triple([mut a, mut b, mut c]) => {
322                let a_len = a.remaining();
323                if at < a_len {
324                    // Split stays entirely in chunk `a`.
325                    let prefix = a.split_to(at);
326                    self.inner = IoBufsInner::Triple([a, b, c]);
327                    return Self::from(prefix);
328                }
329                if at == a_len {
330                    // Exact boundary after `a`.
331                    self.inner = IoBufsInner::Pair([b, c]);
332                    return Self::from(a);
333                }
334
335                let mut remaining = at - a_len;
336                let b_len = b.remaining();
337                if remaining < b_len {
338                    // Split lands inside `b`.
339                    let b_prefix = b.split_to(remaining);
340                    self.inner = IoBufsInner::Pair([b, c]);
341                    return Self {
342                        inner: IoBufsInner::Pair([a, b_prefix]),
343                    };
344                }
345                if remaining == b_len {
346                    // Exact boundary after `b`.
347                    self.inner = IoBufsInner::Single(c);
348                    return Self {
349                        inner: IoBufsInner::Pair([a, b]),
350                    };
351                }
352
353                // Split reaches into `c`.
354                remaining -= b_len;
355                let c_prefix = c.split_to(remaining);
356                self.inner = IoBufsInner::Single(c);
357                Self {
358                    inner: IoBufsInner::Triple([a, b, c_prefix]),
359                }
360            }
361            IoBufsInner::Chunked(mut bufs) => {
362                let mut remaining = at;
363                let mut out = VecDeque::new();
364
365                while remaining > 0 {
366                    let mut front = bufs.pop_front().expect("split_to out of bounds");
367                    let avail = front.remaining();
368                    if avail == 0 {
369                        // Canonical chunked state should not contain empties.
370                        continue;
371                    }
372                    if remaining < avail {
373                        // Split inside this chunk: keep suffix in `self`, move prefix to output.
374                        let prefix = front.split_to(remaining);
375                        out.push_back(prefix);
376                        bufs.push_front(front);
377                        break;
378                    }
379
380                    // Consume this full chunk into the output prefix.
381                    out.push_back(front);
382                    remaining -= avail;
383                }
384
385                self.inner = if bufs.len() >= 4 {
386                    IoBufsInner::Chunked(bufs)
387                } else {
388                    Self::from_chunks_iter(bufs).inner
389                };
390
391                if out.len() >= 4 {
392                    Self {
393                        inner: IoBufsInner::Chunked(out),
394                    }
395                } else {
396                    Self::from_chunks_iter(out)
397                }
398            }
399        }
400    }
401
402    /// Coalesce all remaining bytes into a single contiguous [`IoBuf`].
403    ///
404    /// Zero-copy if only one buffer. Copies into one native heap allocation
405    /// if multiple buffers, so the result supports zero-copy
406    /// [`IoBuf::try_into_mut`].
407    #[inline]
408    pub fn coalesce(self) -> IoBuf {
409        match self.inner {
410            IoBufsInner::Single(buf) => buf,
411            inner => {
412                let bufs = Self { inner };
413                let mut out = IoBufMut::with_capacity(bufs.remaining());
414                bufs.for_each_chunk(|chunk| out.put_slice(chunk));
415                out.freeze()
416            }
417        }
418    }
419
420    /// Coalesce all remaining bytes into a single contiguous [`IoBuf`], using the pool
421    /// for allocation if multiple buffers need to be merged.
422    ///
423    /// Zero-copy if only one buffer. Uses pool allocation if multiple buffers.
424    pub fn coalesce_with_pool(self, pool: &BufferPool) -> IoBuf {
425        match self.inner {
426            IoBufsInner::Single(buf) => buf,
427            IoBufsInner::Pair([a, b]) => {
428                let total_len = a.remaining().saturating_add(b.remaining());
429                let mut result = pool.alloc(total_len);
430                result.put_slice(a.as_ref());
431                result.put_slice(b.as_ref());
432                result.freeze()
433            }
434            IoBufsInner::Triple([a, b, c]) => {
435                let total_len = a
436                    .remaining()
437                    .saturating_add(b.remaining())
438                    .saturating_add(c.remaining());
439                let mut result = pool.alloc(total_len);
440                result.put_slice(a.as_ref());
441                result.put_slice(b.as_ref());
442                result.put_slice(c.as_ref());
443                result.freeze()
444            }
445            IoBufsInner::Chunked(bufs) => {
446                let total_len: usize = bufs
447                    .iter()
448                    .map(|b| b.remaining())
449                    .fold(0, usize::saturating_add);
450                let mut result = pool.alloc(total_len);
451                for buf in bufs {
452                    result.put_slice(buf.as_ref());
453                }
454                result.freeze()
455            }
456        }
457    }
458}
459
460impl Buf for IoBufs {
461    #[inline]
462    fn remaining(&self) -> usize {
463        match &self.inner {
464            IoBufsInner::Single(buf) => buf.remaining(),
465            IoBufsInner::Pair([a, b]) => a.remaining().saturating_add(b.remaining()),
466            IoBufsInner::Triple([a, b, c]) => a
467                .remaining()
468                .saturating_add(b.remaining())
469                .saturating_add(c.remaining()),
470            IoBufsInner::Chunked(bufs) => bufs
471                .iter()
472                .map(|b| b.remaining())
473                .fold(0, usize::saturating_add),
474        }
475    }
476
477    #[inline]
478    fn chunk(&self) -> &[u8] {
479        match &self.inner {
480            IoBufsInner::Single(buf) => buf.chunk(),
481            IoBufsInner::Pair([a, b]) => {
482                if a.remaining() > 0 {
483                    a.chunk()
484                } else if b.remaining() > 0 {
485                    b.chunk()
486                } else {
487                    &[]
488                }
489            }
490            IoBufsInner::Triple([a, b, c]) => {
491                if a.remaining() > 0 {
492                    a.chunk()
493                } else if b.remaining() > 0 {
494                    b.chunk()
495                } else if c.remaining() > 0 {
496                    c.chunk()
497                } else {
498                    &[]
499                }
500            }
501            IoBufsInner::Chunked(bufs) => {
502                for buf in bufs.iter() {
503                    if buf.remaining() > 0 {
504                        return buf.chunk();
505                    }
506                }
507                &[]
508            }
509        }
510    }
511
512    #[inline]
513    fn chunks_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize {
514        if dst.is_empty() {
515            return 0;
516        }
517
518        match &self.inner {
519            IoBufsInner::Single(buf) => {
520                let chunk = buf.chunk();
521                if !chunk.is_empty() {
522                    dst[0] = IoSlice::new(chunk);
523                    return 1;
524                }
525                0
526            }
527            IoBufsInner::Pair([a, b]) => fill_vectored_from_chunks(dst, [a.chunk(), b.chunk()]),
528            IoBufsInner::Triple([a, b, c]) => {
529                fill_vectored_from_chunks(dst, [a.chunk(), b.chunk(), c.chunk()])
530            }
531            IoBufsInner::Chunked(bufs) => {
532                fill_vectored_from_chunks(dst, bufs.iter().map(|buf| buf.chunk()))
533            }
534        }
535    }
536
537    #[inline]
538    fn advance(&mut self, cnt: usize) {
539        let should_canonicalize = match &mut self.inner {
540            IoBufsInner::Single(buf) => {
541                buf.advance(cnt);
542                false
543            }
544            IoBufsInner::Pair(pair) => advance_small_chunks(pair.as_mut_slice(), cnt),
545            IoBufsInner::Triple(triple) => advance_small_chunks(triple.as_mut_slice(), cnt),
546            IoBufsInner::Chunked(bufs) => {
547                advance_chunked_front(bufs, cnt);
548                bufs.len() <= 3
549            }
550        };
551
552        if should_canonicalize {
553            self.canonicalize();
554        }
555    }
556
557    #[inline]
558    fn copy_to_bytes(&mut self, len: usize) -> Bytes {
559        let (result, needs_canonicalize) = match &mut self.inner {
560            IoBufsInner::Single(buf) => return buf.copy_to_bytes(len),
561            IoBufsInner::Pair(pair) => {
562                copy_to_bytes_small_chunks(pair, len, "IoBufs::copy_to_bytes: not enough data")
563            }
564            IoBufsInner::Triple(triple) => {
565                copy_to_bytes_small_chunks(triple, len, "IoBufs::copy_to_bytes: not enough data")
566            }
567            IoBufsInner::Chunked(bufs) => {
568                copy_to_bytes_chunked(bufs, len, "IoBufs::copy_to_bytes: not enough data")
569            }
570        };
571
572        if needs_canonicalize {
573            self.canonicalize();
574        }
575
576        result
577    }
578}
579
580/// Zero-copy: wraps the buffer as the single chunk.
581impl From<IoBuf> for IoBufs {
582    fn from(buf: IoBuf) -> Self {
583        Self {
584            inner: IoBufsInner::Single(buf),
585        }
586    }
587}
588
589/// Zero-copy: freezes the buffer and wraps it as the single chunk.
590impl From<IoBufMut> for IoBufs {
591    fn from(buf: IoBufMut) -> Self {
592        Self {
593            inner: IoBufsInner::Single(buf.freeze()),
594        }
595    }
596}
597
598/// Zero-copy via `From<Bytes> for IoBuf`.
599impl From<Bytes> for IoBufs {
600    fn from(bytes: Bytes) -> Self {
601        Self::from(IoBuf::from(bytes))
602    }
603}
604
605/// Zero-copy via `From<BytesMut> for IoBuf`.
606impl From<BytesMut> for IoBufs {
607    fn from(bytes: BytesMut) -> Self {
608        Self::from(IoBuf::from(bytes))
609    }
610}
611
612/// Zero-copy via `From<Vec<u8>> for IoBuf`.
613impl From<Vec<u8>> for IoBufs {
614    fn from(vec: Vec<u8>) -> Self {
615        Self::from(IoBuf::from(vec))
616    }
617}
618
619/// Zero-copy: collects the chunks, dropping empty ones.
620impl From<Vec<IoBuf>> for IoBufs {
621    fn from(bufs: Vec<IoBuf>) -> Self {
622        Self::from_chunks_iter(bufs)
623    }
624}
625
626/// Zero-copy: creates a static view with no owner.
627impl<const N: usize> From<&'static [u8; N]> for IoBufs {
628    fn from(array: &'static [u8; N]) -> Self {
629        Self::from(IoBuf::from(array))
630    }
631}
632
633/// Zero-copy: creates a static view with no owner.
634impl From<&'static [u8]> for IoBufs {
635    fn from(slice: &'static [u8]) -> Self {
636        Self::from(IoBuf::from(slice))
637    }
638}
639
640/// Container for one or more mutable buffers.
641///
642/// # Capacity retention
643///
644/// The intended usage is fill-then-read: write into the container (through
645/// [`BufMut`], [`Self::copy_from_slice`], or
646/// [`Blob::read_at_buf`](crate::Blob::read_at_buf)), then consume it through
647/// [`Buf`]. Caller-reserved write capacity generally survives read
648/// operations, with three exceptions:
649/// - The deque-backed read paths (four or more chunks) skip past a chunk
650///   with no readable bytes by popping it, so a never-filled chunk ordered
651///   before readable data loses its capacity when a read crosses it.
652/// - The same paths pop any chunk whose readable bytes a read fully
653///   consumes, releasing its writable tail. The two and three-chunk shapes
654///   advance in place and retain such tails, so `remaining_mut()` after an
655///   identical read can differ by shape.
656/// - A `copy_to_bytes` that exactly drains the front chunk's readable bytes
657///   consumes that chunk's whole handle on every shape (see [`IoBufMut`]'s
658///   `copy_to_bytes` doc), so spare capacity behind an exactly-drained chunk
659///   is released rather than retained.
660///
661/// Interleaving writes after reads is outside this contract: a read can
662/// leave a drained chunk's surviving tail ordered before later readable
663/// bytes, and a subsequent [`BufMut`] write fills that tail first.
664#[derive(Debug)]
665pub struct IoBufsMut {
666    inner: IoBufsMutInner,
667}
668
669/// Internal mutable representation.
670///
671/// Construction and canonicalization keep every chunk that still owns
672/// storage (`capacity() > 0`), readable or not, so caller-reserved write
673/// capacity generally survives read operations. The reader-facing rules and
674/// the accepted exceptions are documented on [`IoBufsMut`] under "Capacity
675/// retention". Only fully-drained chunks (capacity consumed by `advance`)
676/// and empty defaults are removed as the shape collapses.
677#[derive(Debug)]
678enum IoBufsMutInner {
679    /// Single buffer (common case, no allocation).
680    Single(IoBufMut),
681    /// Two buffers (fast path, no VecDeque allocation).
682    Pair([IoBufMut; 2]),
683    /// Three buffers (fast path, no VecDeque allocation).
684    Triple([IoBufMut; 3]),
685    /// Four or more buffers.
686    Chunked(VecDeque<IoBufMut>),
687}
688
689impl Default for IoBufsMut {
690    fn default() -> Self {
691        Self {
692            inner: IoBufsMutInner::Single(IoBufMut::default()),
693        }
694    }
695}
696
697impl IoBufsMut {
698    /// Build mutable chunk storage from already-filtered chunks.
699    ///
700    /// This helper intentionally does not filter. Callers route through
701    /// [`Self::from_writable_chunks_iter`] so storage-owning chunks are kept.
702    fn from_chunks_iter(chunks: impl IntoIterator<Item = IoBufMut>) -> Self {
703        let mut iter = chunks.into_iter();
704        let first = match iter.next() {
705            Some(first) => first,
706            None => return Self::default(),
707        };
708        let second = match iter.next() {
709            Some(second) => second,
710            None => {
711                return Self {
712                    inner: IoBufsMutInner::Single(first),
713                };
714            }
715        };
716        let third = match iter.next() {
717            Some(third) => third,
718            None => {
719                return Self {
720                    inner: IoBufsMutInner::Pair([first, second]),
721                };
722            }
723        };
724        let fourth = match iter.next() {
725            Some(fourth) => fourth,
726            None => {
727                return Self {
728                    inner: IoBufsMutInner::Triple([first, second, third]),
729                };
730            }
731        };
732
733        let mut bufs = VecDeque::with_capacity(4);
734        bufs.push_back(first);
735        bufs.push_back(second);
736        bufs.push_back(third);
737        bufs.push_back(fourth);
738        bufs.extend(iter);
739        Self {
740            inner: IoBufsMutInner::Chunked(bufs),
741        }
742    }
743
744    /// Build canonical mutable chunk storage from writable chunks.
745    ///
746    /// Keeps chunks that still own storage, readable or not (`capacity()`
747    /// covers both readable bytes and the writable tail), so a never-filled
748    /// chunk's reserved capacity is not discarded. Fully-drained chunks
749    /// (capacity consumed by `advance`) and empty defaults are removed.
750    fn from_writable_chunks_iter(chunks: impl IntoIterator<Item = IoBufMut>) -> Self {
751        Self::from_chunks_iter(chunks.into_iter().filter(|buf| buf.capacity() > 0))
752    }
753
754    /// Re-establish canonical mutable representation invariants.
755    ///
756    /// Uses the same storage-keeping filter as construction: read operations
757    /// should not change `remaining_mut()` (see the [`IoBufsMutInner`] doc
758    /// for the accepted exceptions), so chunks that were drained of readable
759    /// bytes but still own writable capacity survive.
760    fn canonicalize(&mut self) {
761        let inner = std::mem::replace(&mut self.inner, IoBufsMutInner::Single(IoBufMut::default()));
762        self.inner = match inner {
763            IoBufsMutInner::Single(buf) => IoBufsMutInner::Single(buf),
764            IoBufsMutInner::Pair([a, b]) => Self::from_writable_chunks_iter([a, b]).inner,
765            IoBufsMutInner::Triple([a, b, c]) => Self::from_writable_chunks_iter([a, b, c]).inner,
766            IoBufsMutInner::Chunked(bufs) => Self::from_writable_chunks_iter(bufs).inner,
767        };
768    }
769
770    #[inline]
771    fn for_each_chunk_mut(&mut self, mut f: impl FnMut(&mut IoBufMut)) {
772        match &mut self.inner {
773            IoBufsMutInner::Single(buf) => f(buf),
774            IoBufsMutInner::Pair(pair) => {
775                for buf in pair.iter_mut() {
776                    f(buf);
777                }
778            }
779            IoBufsMutInner::Triple(triple) => {
780                for buf in triple.iter_mut() {
781                    f(buf);
782                }
783            }
784            IoBufsMutInner::Chunked(bufs) => {
785                for buf in bufs.iter_mut() {
786                    f(buf);
787                }
788            }
789        }
790    }
791
792    /// Returns a reference to the single contiguous buffer, if present.
793    ///
794    /// Returns `Some` only when this is currently represented as one chunk.
795    pub const fn as_single(&self) -> Option<&IoBufMut> {
796        match &self.inner {
797            IoBufsMutInner::Single(buf) => Some(buf),
798            _ => None,
799        }
800    }
801
802    /// Returns a mutable reference to the single contiguous buffer, if present.
803    ///
804    /// Returns `Some` only when this is currently represented as one chunk.
805    pub const fn as_single_mut(&mut self) -> Option<&mut IoBufMut> {
806        match &mut self.inner {
807            IoBufsMutInner::Single(buf) => Some(buf),
808            _ => None,
809        }
810    }
811
812    /// Consume this container and return the single buffer if present.
813    ///
814    /// Returns `Ok(IoBufMut)` only when readable data is represented as one
815    /// chunk. Returns `Err(Self)` with the original container otherwise.
816    #[allow(clippy::result_large_err)]
817    pub fn try_into_single(self) -> Result<IoBufMut, Self> {
818        match self.inner {
819            IoBufsMutInner::Single(buf) => Ok(buf),
820            inner => Err(Self { inner }),
821        }
822    }
823
824    /// Number of bytes remaining across all buffers.
825    #[inline]
826    pub fn len(&self) -> usize {
827        self.remaining()
828    }
829
830    /// Whether all buffers are empty.
831    #[inline]
832    pub fn is_empty(&self) -> bool {
833        self.remaining() == 0
834    }
835
836    /// Whether this contains a single contiguous buffer.
837    ///
838    /// When true, `chunk()` returns all remaining bytes.
839    #[inline]
840    pub const fn is_single(&self) -> bool {
841        matches!(self.inner, IoBufsMutInner::Single(_))
842    }
843
844    /// Freeze into immutable [`IoBufs`].
845    pub fn freeze(self) -> IoBufs {
846        match self.inner {
847            IoBufsMutInner::Single(buf) => IoBufs::from(buf.freeze()),
848            IoBufsMutInner::Pair([a, b]) => IoBufs::from_chunks_iter([a.freeze(), b.freeze()]),
849            IoBufsMutInner::Triple([a, b, c]) => {
850                IoBufs::from_chunks_iter([a.freeze(), b.freeze(), c.freeze()])
851            }
852            IoBufsMutInner::Chunked(bufs) => {
853                IoBufs::from_chunks_iter(bufs.into_iter().map(IoBufMut::freeze))
854            }
855        }
856    }
857
858    fn coalesce_with<F>(self, allocate: F) -> IoBufMut
859    where
860        F: FnOnce(usize) -> IoBufMut,
861    {
862        match self.inner {
863            IoBufsMutInner::Single(buf) => buf,
864            IoBufsMutInner::Pair([a, b]) => {
865                let total_len = a.len().saturating_add(b.len());
866                let mut result = allocate(total_len);
867                result.put_slice(a.as_ref());
868                result.put_slice(b.as_ref());
869                result
870            }
871            IoBufsMutInner::Triple([a, b, c]) => {
872                let total_len = a.len().saturating_add(b.len()).saturating_add(c.len());
873                let mut result = allocate(total_len);
874                result.put_slice(a.as_ref());
875                result.put_slice(b.as_ref());
876                result.put_slice(c.as_ref());
877                result
878            }
879            IoBufsMutInner::Chunked(bufs) => {
880                let total_len: usize = bufs.iter().map(|b| b.len()).fold(0, usize::saturating_add);
881                let mut result = allocate(total_len);
882                for buf in bufs {
883                    result.put_slice(buf.as_ref());
884                }
885                result
886            }
887        }
888    }
889
890    /// Coalesce all buffers into a single contiguous [`IoBufMut`].
891    ///
892    /// Zero-copy if only one buffer. Copies if multiple buffers.
893    pub fn coalesce(self) -> IoBufMut {
894        self.coalesce_with(IoBufMut::with_capacity)
895    }
896
897    /// Coalesce all buffers into a single contiguous [`IoBufMut`], using the pool
898    /// for allocation if multiple buffers need to be merged.
899    ///
900    /// Zero-copy if only one buffer. Uses pool allocation if multiple buffers.
901    pub fn coalesce_with_pool(self, pool: &BufferPool) -> IoBufMut {
902        self.coalesce_with(|len| pool.alloc(len))
903    }
904
905    /// Coalesce all buffers into a single contiguous [`IoBufMut`] with extra
906    /// capacity, using the pool for allocation.
907    ///
908    /// Zero-copy if single buffer with sufficient spare capacity.
909    pub fn coalesce_with_pool_extra(self, pool: &BufferPool, extra: usize) -> IoBufMut {
910        match self.inner {
911            IoBufsMutInner::Single(buf) if buf.capacity() - buf.len() >= extra => buf,
912            IoBufsMutInner::Single(buf) => {
913                let mut result = pool.alloc(buf.len() + extra);
914                result.put_slice(buf.as_ref());
915                result
916            }
917            IoBufsMutInner::Pair([a, b]) => {
918                let total = a.len().saturating_add(b.len());
919                let mut result = pool.alloc(total + extra);
920                result.put_slice(a.as_ref());
921                result.put_slice(b.as_ref());
922                result
923            }
924            IoBufsMutInner::Triple([a, b, c]) => {
925                let total = a.len().saturating_add(b.len()).saturating_add(c.len());
926                let mut result = pool.alloc(total + extra);
927                result.put_slice(a.as_ref());
928                result.put_slice(b.as_ref());
929                result.put_slice(c.as_ref());
930                result
931            }
932            IoBufsMutInner::Chunked(bufs) => {
933                let total: usize = bufs.iter().map(|b| b.len()).fold(0, usize::saturating_add);
934                let mut result = pool.alloc(total + extra);
935                for buf in bufs {
936                    result.put_slice(buf.as_ref());
937                }
938                result
939            }
940        }
941    }
942
943    /// Returns the total capacity across all buffers.
944    pub fn capacity(&self) -> usize {
945        match &self.inner {
946            IoBufsMutInner::Single(buf) => buf.capacity(),
947            IoBufsMutInner::Pair([a, b]) => a.capacity().saturating_add(b.capacity()),
948            IoBufsMutInner::Triple([a, b, c]) => a
949                .capacity()
950                .saturating_add(b.capacity())
951                .saturating_add(c.capacity()),
952            IoBufsMutInner::Chunked(bufs) => bufs
953                .iter()
954                .map(|b| b.capacity())
955                .fold(0, usize::saturating_add),
956        }
957    }
958
959    /// Sets the length of the buffer(s) to `len`, distributing across chunks
960    /// while preserving the current chunk layout.
961    ///
962    /// This is useful for APIs that must fill caller-provided buffer structure
963    /// in place (for example [`Blob::read_at_buf`](crate::Blob::read_at_buf)).
964    ///
965    /// # Safety
966    ///
967    /// Caller must initialize all `len` bytes before the buffer is read.
968    ///
969    /// # Panics
970    ///
971    /// Panics if `len` exceeds total capacity.
972    pub(crate) unsafe fn set_len(&mut self, len: usize) {
973        let capacity = self.capacity();
974        assert!(
975            len <= capacity,
976            "set_len({len}) exceeds capacity({capacity})"
977        );
978        let mut remaining = len;
979        self.for_each_chunk_mut(|buf| {
980            let cap = buf.capacity();
981            let to_set = remaining.min(cap);
982            // SAFETY: forwarded from this method's contract. The caller
983            // initializes all `len` bytes before any read.
984            unsafe { buf.set_len(to_set) };
985            remaining -= to_set;
986        });
987    }
988
989    /// Copy data from a slice into the buffers.
990    ///
991    /// # Panics
992    ///
993    /// Panics if the slice length doesn't match the total buffer length.
994    pub fn copy_from_slice(&mut self, src: &[u8]) {
995        assert_eq!(
996            src.len(),
997            self.len(),
998            "source slice length must match buffer length"
999        );
1000        let mut offset = 0;
1001        self.for_each_chunk_mut(|buf| {
1002            let len = buf.len();
1003            buf.as_mut().copy_from_slice(&src[offset..offset + len]);
1004            offset += len;
1005        });
1006    }
1007}
1008
1009impl Buf for IoBufsMut {
1010    #[inline]
1011    fn remaining(&self) -> usize {
1012        match &self.inner {
1013            IoBufsMutInner::Single(buf) => buf.remaining(),
1014            IoBufsMutInner::Pair([a, b]) => a.remaining().saturating_add(b.remaining()),
1015            IoBufsMutInner::Triple([a, b, c]) => a
1016                .remaining()
1017                .saturating_add(b.remaining())
1018                .saturating_add(c.remaining()),
1019            IoBufsMutInner::Chunked(bufs) => bufs
1020                .iter()
1021                .map(|b| b.remaining())
1022                .fold(0, usize::saturating_add),
1023        }
1024    }
1025
1026    #[inline]
1027    fn chunk(&self) -> &[u8] {
1028        match &self.inner {
1029            IoBufsMutInner::Single(buf) => buf.chunk(),
1030            IoBufsMutInner::Pair([a, b]) => {
1031                if a.remaining() > 0 {
1032                    a.chunk()
1033                } else if b.remaining() > 0 {
1034                    b.chunk()
1035                } else {
1036                    &[]
1037                }
1038            }
1039            IoBufsMutInner::Triple([a, b, c]) => {
1040                if a.remaining() > 0 {
1041                    a.chunk()
1042                } else if b.remaining() > 0 {
1043                    b.chunk()
1044                } else if c.remaining() > 0 {
1045                    c.chunk()
1046                } else {
1047                    &[]
1048                }
1049            }
1050            IoBufsMutInner::Chunked(bufs) => {
1051                for buf in bufs.iter() {
1052                    if buf.remaining() > 0 {
1053                        return buf.chunk();
1054                    }
1055                }
1056                &[]
1057            }
1058        }
1059    }
1060
1061    #[inline]
1062    fn chunks_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize {
1063        if dst.is_empty() {
1064            return 0;
1065        }
1066
1067        match &self.inner {
1068            IoBufsMutInner::Single(buf) => {
1069                let chunk = buf.chunk();
1070                if !chunk.is_empty() {
1071                    dst[0] = IoSlice::new(chunk);
1072                    return 1;
1073                }
1074                0
1075            }
1076            IoBufsMutInner::Pair([a, b]) => fill_vectored_from_chunks(dst, [a.chunk(), b.chunk()]),
1077            IoBufsMutInner::Triple([a, b, c]) => {
1078                fill_vectored_from_chunks(dst, [a.chunk(), b.chunk(), c.chunk()])
1079            }
1080            IoBufsMutInner::Chunked(bufs) => {
1081                fill_vectored_from_chunks(dst, bufs.iter().map(|buf| buf.chunk()))
1082            }
1083        }
1084    }
1085
1086    #[inline]
1087    fn advance(&mut self, cnt: usize) {
1088        let should_canonicalize = match &mut self.inner {
1089            IoBufsMutInner::Single(buf) => {
1090                buf.advance(cnt);
1091                false
1092            }
1093            IoBufsMutInner::Pair(pair) => advance_small_chunks(pair.as_mut_slice(), cnt),
1094            IoBufsMutInner::Triple(triple) => advance_small_chunks(triple.as_mut_slice(), cnt),
1095            IoBufsMutInner::Chunked(bufs) => {
1096                advance_chunked_front(bufs, cnt);
1097                bufs.len() <= 3
1098            }
1099        };
1100
1101        if should_canonicalize {
1102            self.canonicalize();
1103        }
1104    }
1105
1106    #[inline]
1107    fn copy_to_bytes(&mut self, len: usize) -> Bytes {
1108        // Zero-length drains must not disturb chunk state: the deque-backed
1109        // path skips readable-empty chunks by popping them, which would
1110        // discard a never-filled chunk's reserved capacity.
1111        if len == 0 {
1112            return Bytes::new();
1113        }
1114        let (result, needs_canonicalize) = match &mut self.inner {
1115            IoBufsMutInner::Single(buf) => return buf.copy_to_bytes(len),
1116            IoBufsMutInner::Pair(pair) => {
1117                copy_to_bytes_small_chunks(pair, len, "IoBufsMut::copy_to_bytes: not enough data")
1118            }
1119            IoBufsMutInner::Triple(triple) => {
1120                copy_to_bytes_small_chunks(triple, len, "IoBufsMut::copy_to_bytes: not enough data")
1121            }
1122            IoBufsMutInner::Chunked(bufs) => {
1123                copy_to_bytes_chunked(bufs, len, "IoBufsMut::copy_to_bytes: not enough data")
1124            }
1125        };
1126
1127        if needs_canonicalize {
1128            self.canonicalize();
1129        }
1130
1131        result
1132    }
1133}
1134
1135// SAFETY: Delegates to IoBufMut which implements BufMut safely.
1136unsafe impl BufMut for IoBufsMut {
1137    #[inline]
1138    fn remaining_mut(&self) -> usize {
1139        match &self.inner {
1140            IoBufsMutInner::Single(buf) => buf.remaining_mut(),
1141            IoBufsMutInner::Pair([a, b]) => a.remaining_mut().saturating_add(b.remaining_mut()),
1142            IoBufsMutInner::Triple([a, b, c]) => a
1143                .remaining_mut()
1144                .saturating_add(b.remaining_mut())
1145                .saturating_add(c.remaining_mut()),
1146            IoBufsMutInner::Chunked(bufs) => bufs
1147                .iter()
1148                .map(|b| b.remaining_mut())
1149                .fold(0, usize::saturating_add),
1150        }
1151    }
1152
1153    #[inline]
1154    unsafe fn advance_mut(&mut self, cnt: usize) {
1155        // SAFETY: The caller guarantees `cnt <= self.remaining_mut()`, so each
1156        // delegated advance remains within the writable chunks.
1157        unsafe {
1158            // On failure, every writable byte was consumed before the chunks ran
1159            // out, so the advanced amount (`cnt - remaining`) is exactly what was
1160            // available.
1161            let mut remaining = cnt;
1162            let advanced = match &mut self.inner {
1163                IoBufsMutInner::Single(buf) => {
1164                    buf.advance_mut(cnt);
1165                    return;
1166                }
1167                IoBufsMutInner::Pair(pair) => advance_mut_in_chunks(pair, &mut remaining),
1168                IoBufsMutInner::Triple(triple) => advance_mut_in_chunks(triple, &mut remaining),
1169                IoBufsMutInner::Chunked(bufs) => {
1170                    let (first, second) = bufs.as_mut_slices();
1171                    advance_mut_in_chunks(first, &mut remaining)
1172                        || advance_mut_in_chunks(second, &mut remaining)
1173                }
1174            };
1175            if !advanced {
1176                panic_advance(cnt, cnt - remaining);
1177            }
1178        }
1179    }
1180
1181    #[inline]
1182    fn chunk_mut(&mut self) -> &mut bytes::buf::UninitSlice {
1183        match &mut self.inner {
1184            IoBufsMutInner::Single(buf) => buf.chunk_mut(),
1185            IoBufsMutInner::Pair(pair) => {
1186                if pair[0].remaining_mut() > 0 {
1187                    pair[0].chunk_mut()
1188                } else if pair[1].remaining_mut() > 0 {
1189                    pair[1].chunk_mut()
1190                } else {
1191                    bytes::buf::UninitSlice::new(&mut [])
1192                }
1193            }
1194            IoBufsMutInner::Triple(triple) => {
1195                if triple[0].remaining_mut() > 0 {
1196                    triple[0].chunk_mut()
1197                } else if triple[1].remaining_mut() > 0 {
1198                    triple[1].chunk_mut()
1199                } else if triple[2].remaining_mut() > 0 {
1200                    triple[2].chunk_mut()
1201                } else {
1202                    bytes::buf::UninitSlice::new(&mut [])
1203                }
1204            }
1205            IoBufsMutInner::Chunked(bufs) => {
1206                for buf in bufs.iter_mut() {
1207                    if buf.remaining_mut() > 0 {
1208                        return buf.chunk_mut();
1209                    }
1210                }
1211                bytes::buf::UninitSlice::new(&mut [])
1212            }
1213        }
1214    }
1215}
1216
1217/// Zero-copy: wraps the buffer as the single chunk.
1218impl From<IoBufMut> for IoBufsMut {
1219    fn from(buf: IoBufMut) -> Self {
1220        Self {
1221            inner: IoBufsMutInner::Single(buf),
1222        }
1223    }
1224}
1225
1226/// Convert a [`Vec<u8>`] into a single-buffer [`IoBufsMut`].
1227///
1228/// Copies via `From<Vec<u8>> for IoBufMut`, preserving the vec's capacity
1229/// (see that impl for the copy-vs-adoption rationale).
1230impl From<Vec<u8>> for IoBufsMut {
1231    fn from(vec: Vec<u8>) -> Self {
1232        Self {
1233            inner: IoBufsMutInner::Single(IoBufMut::from(vec)),
1234        }
1235    }
1236}
1237
1238/// Copies via `From<BytesMut> for IoBufMut`, preserving the caller's
1239/// capacity.
1240impl From<BytesMut> for IoBufsMut {
1241    fn from(bytes: BytesMut) -> Self {
1242        Self {
1243            inner: IoBufsMutInner::Single(IoBufMut::from(bytes)),
1244        }
1245    }
1246}
1247
1248/// Zero-copy: collects the chunks, dropping zero-capacity ones.
1249impl From<Vec<IoBufMut>> for IoBufsMut {
1250    fn from(bufs: Vec<IoBufMut>) -> Self {
1251        Self::from_writable_chunks_iter(bufs)
1252    }
1253}
1254
1255/// Copies via `From<[u8; N]> for IoBufMut`.
1256impl<const N: usize> From<[u8; N]> for IoBufsMut {
1257    fn from(array: [u8; N]) -> Self {
1258        Self {
1259            inner: IoBufsMutInner::Single(IoBufMut::from(array)),
1260        }
1261    }
1262}
1263
1264/// Drain `len` readable bytes from a small fixed chunk array (`Pair`/`Triple`).
1265///
1266/// Returns drained bytes plus whether the caller should canonicalize afterward.
1267#[inline]
1268fn copy_to_bytes_small_chunks<B: Buf, const N: usize>(
1269    chunks: &mut [B; N],
1270    len: usize,
1271    not_enough_data_msg: &str,
1272) -> (Bytes, bool) {
1273    let total = chunks
1274        .iter()
1275        .map(|buf| buf.remaining())
1276        .fold(0, usize::saturating_add);
1277    assert!(total >= len, "{not_enough_data_msg}");
1278
1279    if chunks[0].remaining() >= len {
1280        let bytes = chunks[0].copy_to_bytes(len);
1281        return (bytes, chunks[0].remaining() == 0);
1282    }
1283
1284    let mut out = BytesMut::with_capacity(len);
1285    let mut remaining = len;
1286    for buf in chunks.iter_mut() {
1287        if remaining == 0 {
1288            break;
1289        }
1290        let to_copy = remaining.min(buf.remaining());
1291        out.extend_from_slice(&buf.chunk()[..to_copy]);
1292        buf.advance(to_copy);
1293        remaining -= to_copy;
1294    }
1295
1296    // Slow path always consumes past chunk 0, so canonicalization is required.
1297    (out.freeze(), true)
1298}
1299
1300/// Drain `len` readable bytes from a deque-backed chunk representation.
1301///
1302/// Returns drained bytes plus whether the caller should canonicalize afterward.
1303#[inline]
1304fn copy_to_bytes_chunked<B: Buf>(
1305    bufs: &mut VecDeque<B>,
1306    len: usize,
1307    not_enough_data_msg: &str,
1308) -> (Bytes, bool) {
1309    while bufs.front().is_some_and(|buf| buf.remaining() == 0) {
1310        bufs.pop_front();
1311    }
1312
1313    if bufs.front().is_none() {
1314        assert_eq!(len, 0, "{not_enough_data_msg}");
1315        // The deque is empty now, so the container must collapse back to the
1316        // canonical Single representation.
1317        return (Bytes::new(), true);
1318    }
1319
1320    if bufs.front().is_some_and(|front| front.remaining() >= len) {
1321        let front = bufs.front_mut().expect("front checked above");
1322        let bytes = front.copy_to_bytes(len);
1323        if front.remaining() == 0 {
1324            bufs.pop_front();
1325        }
1326        return (bytes, bufs.len() <= 3);
1327    }
1328
1329    let total = bufs
1330        .iter()
1331        .map(|buf| buf.remaining())
1332        .fold(0, usize::saturating_add);
1333    assert!(total >= len, "{not_enough_data_msg}");
1334
1335    let mut out = BytesMut::with_capacity(len);
1336    let mut remaining = len;
1337    while remaining > 0 {
1338        let front = bufs
1339            .front_mut()
1340            .expect("remaining > 0 implies non-empty bufs");
1341        let to_copy = remaining.min(front.remaining());
1342        out.extend_from_slice(&front.chunk()[..to_copy]);
1343        front.advance(to_copy);
1344        if front.remaining() == 0 {
1345            bufs.pop_front();
1346        }
1347        remaining -= to_copy;
1348    }
1349
1350    (out.freeze(), bufs.len() <= 3)
1351}
1352
1353/// Advance across a [`VecDeque`] of chunks by consuming from the front.
1354#[inline]
1355fn advance_chunked_front<B: Buf>(bufs: &mut VecDeque<B>, mut cnt: usize) {
1356    while cnt > 0 {
1357        let front = bufs.front_mut().expect("cannot advance past end of buffer");
1358        let avail = front.remaining();
1359        if avail == 0 {
1360            bufs.pop_front();
1361            continue;
1362        }
1363        if cnt < avail {
1364            front.advance(cnt);
1365            break;
1366        }
1367        front.advance(avail);
1368        bufs.pop_front();
1369        cnt -= avail;
1370    }
1371}
1372
1373/// Advance across a small fixed set of chunks (`Pair`/`Triple`).
1374///
1375/// Returns `true` when one or more chunks became (or were) empty, so callers
1376/// can canonicalize once after the operation.
1377#[inline]
1378fn advance_small_chunks<B: Buf>(chunks: &mut [B], mut cnt: usize) -> bool {
1379    let mut idx = 0;
1380    let mut needs_canonicalize = false;
1381
1382    while cnt > 0 {
1383        let chunk = chunks
1384            .get_mut(idx)
1385            .expect("cannot advance past end of buffer");
1386        let avail = chunk.remaining();
1387        if avail == 0 {
1388            idx += 1;
1389            needs_canonicalize = true;
1390            continue;
1391        }
1392        if cnt < avail {
1393            chunk.advance(cnt);
1394            return needs_canonicalize;
1395        }
1396        chunk.advance(avail);
1397        cnt -= avail;
1398        idx += 1;
1399        needs_canonicalize = true;
1400    }
1401
1402    needs_canonicalize
1403}
1404
1405/// Advance writable cursors across `chunks` by up to `*remaining` bytes.
1406///
1407/// Returns `true` when the full request has been satisfied.
1408///
1409/// # Safety
1410///
1411/// Forwards to [`BufMut::advance_mut`], so callers must ensure the advanced
1412/// region has been initialized according to [`BufMut`]'s contract.
1413#[inline]
1414unsafe fn advance_mut_in_chunks<B: BufMut>(chunks: &mut [B], remaining: &mut usize) -> bool {
1415    if *remaining == 0 {
1416        return true;
1417    }
1418
1419    for buf in chunks.iter_mut() {
1420        let avail = buf.chunk_mut().len();
1421        if avail == 0 {
1422            continue;
1423        }
1424        if *remaining <= avail {
1425            // SAFETY: Upheld by this function's safety contract.
1426            unsafe { buf.advance_mut(*remaining) };
1427            *remaining = 0;
1428            return true;
1429        }
1430        // SAFETY: Upheld by this function's safety contract.
1431        unsafe { buf.advance_mut(avail) };
1432        *remaining -= avail;
1433    }
1434    false
1435}
1436
1437/// Fill `dst` with `IoSlice`s built from `chunks`.
1438///
1439/// Empty chunks are skipped. At most `dst.len()` slices are written.
1440/// Returns the number of slices written.
1441#[inline]
1442fn fill_vectored_from_chunks<'a, I>(dst: &mut [IoSlice<'a>], chunks: I) -> usize
1443where
1444    I: IntoIterator<Item = &'a [u8]>,
1445{
1446    let mut written = 0;
1447    for chunk in chunks
1448        .into_iter()
1449        .filter(|chunk| !chunk.is_empty())
1450        .take(dst.len())
1451    {
1452        dst[written] = IoSlice::new(chunk);
1453        written += 1;
1454    }
1455    written
1456}
1457
1458/// Assembles [`IoBufs`] from a mix of inline writes and zero-copy pieces.
1459///
1460/// All inline writes go into a single pool-backed buffer. [`BufsMut::push`]
1461/// records boundaries without flushing. [`Builder::finish`] freezes the buffer
1462/// once and uses [`IoBuf::slice`] to carve it into pieces at the recorded
1463/// boundaries, interleaved with the pushed [`Bytes`].
1464///
1465/// The inline buffer has a fixed capacity set at construction and will not
1466/// grow. Callers must ensure the capacity accounts for all inline
1467/// (non-pushed) bytes that will be written. Exceeding it will panic.
1468///
1469/// ```text
1470/// builder.put_u16(99);                        // inline
1471/// builder.push(shard_payload.clone());        // zero-copy (Arc clone)
1472/// builder.put_u32(checksum);                  // inline
1473/// let output = builder.finish();
1474///
1475/// // output: [ 99 | --- 1 MB shard --- | checksum ]
1476/// //           pool    Arc clone          pool
1477/// //            \________________________/
1478/// //             slices of one allocation
1479/// ```
1480pub struct Builder {
1481    // Single working buffer for all inline writes.
1482    buf: IoBufMut,
1483    // Each entry is (offset_in_buf, pushed_bytes) recording where a push
1484    // interrupts the inline byte stream.
1485    pushes: Vec<(usize, Bytes)>,
1486}
1487
1488impl Builder {
1489    /// Creates a new builder with a fixed-capacity inline buffer.
1490    ///
1491    /// `capacity` is the minimum number of inline bytes the buffer can hold.
1492    /// The pool may round up to a larger size class.
1493    ///
1494    /// # Panics
1495    ///
1496    /// Panics are deferred to the write site: writing more inline bytes than
1497    /// the allocated capacity panics there.
1498    pub fn new(pool: &BufferPool, capacity: NonZeroUsize) -> Self {
1499        Self {
1500            buf: pool.alloc(capacity.get()),
1501            pushes: Vec::new(),
1502        }
1503    }
1504
1505    /// Freezes the inline buffer and assembles [`IoBufs`] by slicing at
1506    /// the recorded push boundaries.
1507    pub fn finish(self) -> IoBufs {
1508        if self.pushes.is_empty() {
1509            return IoBufs::from(self.buf.freeze());
1510        }
1511
1512        let frozen = self.buf.freeze();
1513        let mut result = IoBufs::default();
1514        let mut pos = 0;
1515
1516        for (offset, pushed) in self.pushes {
1517            if offset > pos {
1518                result.append(frozen.slice(pos..offset));
1519            }
1520            // Zero-copy: pushed Bytes (for example a 1 MB shard payload held
1521            // by Arc clone) become external-backed chunks, never a memcpy.
1522            result.append(IoBuf::from(pushed));
1523            pos = offset;
1524        }
1525
1526        if pos < frozen.len() {
1527            result.append(frozen.slice(pos..));
1528        }
1529
1530        result
1531    }
1532}
1533
1534// SAFETY: All methods delegate directly to `self.buf`, a pool-backed
1535// `IoBufMut` with a sound `BufMut` implementation. The inline buffer has
1536// fixed capacity. Writes that exceed it panic in bytes' `BufMut` trait
1537// defaults (which check `remaining_mut`) or, for a direct `advance_mut`,
1538// in `IoBufMut::advance_mut`.
1539unsafe impl BufMut for Builder {
1540    #[inline]
1541    fn remaining_mut(&self) -> usize {
1542        self.buf.remaining_mut()
1543    }
1544
1545    #[inline]
1546    unsafe fn advance_mut(&mut self, cnt: usize) {
1547        // SAFETY: The caller guarantees that `cnt` is within the writable chunk.
1548        unsafe {
1549            self.buf.advance_mut(cnt);
1550        }
1551    }
1552
1553    #[inline]
1554    fn chunk_mut(&mut self) -> &mut bytes::buf::UninitSlice {
1555        self.buf.chunk_mut()
1556    }
1557}
1558
1559impl BufsMut for Builder {
1560    fn push(&mut self, bytes: impl Into<Bytes>) {
1561        let bytes = bytes.into();
1562        if !bytes.is_empty() {
1563            self.pushes.push((self.buf.len(), bytes));
1564        }
1565    }
1566}
1567
1568/// Extension trait for encoding values into pooled I/O buffers.
1569///
1570/// This is useful for hot paths that need to avoid frequent heap allocations
1571/// when serializing values that implement [`Write`] and [`EncodeSize`].
1572pub trait EncodeExt: EncodeSize + Write {
1573    /// Encode this value into an [`IoBufMut`] allocated from `pool`.
1574    ///
1575    /// # Panics
1576    ///
1577    /// Panics if [`EncodeSize::encode_size`] does not match the number of
1578    /// bytes written by [`Write::write`].
1579    fn encode_with_pool_mut(&self, pool: &BufferPool) -> IoBufMut {
1580        let len = self.encode_size();
1581        let mut buf = pool.alloc(len);
1582        self.write(&mut buf);
1583        assert_eq!(
1584            buf.len(),
1585            len,
1586            "write() did not write expected bytes into pooled buffer"
1587        );
1588        buf
1589    }
1590
1591    /// Encode into [`IoBufs`] using pool allocation.
1592    ///
1593    /// Override [`Write::write_bufs`] to avoid copying large [`Bytes`] fields.
1594    ///
1595    /// # Panics
1596    ///
1597    /// Panics if [`Write::write_bufs`] writes more inline bytes than the
1598    /// builder's allocated capacity (at least
1599    /// [`EncodeSize::encode_inline_size`], possibly rounded up to a size
1600    /// class), or if [`EncodeSize::encode_size`] does not match the total
1601    /// bytes written.
1602    fn encode_with_pool(&self, pool: &BufferPool) -> IoBufs {
1603        let len = self.encode_size();
1604        let capacity = NonZeroUsize::new(self.encode_inline_size()).unwrap_or(NonZeroUsize::MIN);
1605        let mut builder = Builder::new(pool, capacity);
1606        self.write_bufs(&mut builder);
1607        let bufs = builder.finish();
1608        assert_eq!(
1609            bufs.remaining(),
1610            len,
1611            "write_bufs() did not write expected bytes"
1612        );
1613        bufs
1614    }
1615}
1616
1617impl<T: EncodeSize + Write> EncodeExt for T {}
1618
1619#[cfg(all(test, not(feature = "loom")))]
1620mod tests {
1621    use super::{super::pool::BufferPoolConfig, *};
1622    use bytes::{Bytes, BytesMut};
1623    use commonware_codec::{Encode, types::lazy::Lazy};
1624    use commonware_utils::range::NonEmptyRange;
1625    use std::collections::{BTreeMap, HashMap};
1626
1627    fn test_pool() -> BufferPool {
1628        cfg_if::cfg_if! {
1629            if #[cfg(miri)] {
1630                // Reduce the class limits to avoid slow atomics under miri.
1631                let pool_config = BufferPoolConfig::for_network()
1632                    .with_pool_min_size(0)
1633                    .with_max_per_class(commonware_utils::NZU32!(32));
1634            } else {
1635                let pool_config = BufferPoolConfig::for_network().with_pool_min_size(0);
1636            }
1637        }
1638        let mut registry = crate::telemetry::metrics::Registry::default();
1639        BufferPool::new(pool_config, &mut registry)
1640    }
1641
1642    fn assert_encode_with_pool_matches_encode<T: Encode + EncodeExt>(value: &T) {
1643        let pool = test_pool();
1644        let mut pooled = value.encode_with_pool(&pool);
1645        let baseline = value.encode();
1646        let mut pooled_bytes = vec![0u8; pooled.remaining()];
1647        pooled.copy_to_slice(&mut pooled_bytes);
1648        assert_eq!(pooled_bytes, baseline.as_ref());
1649    }
1650
1651    #[test]
1652    fn test_iobufs_for_each_chunk_single_and_empty() {
1653        // The Single arm is bypassed by coalesce (which returns the buffer
1654        // directly), so exercise the public method on both Single shapes.
1655        let mut seen = Vec::new();
1656        IoBufs::from(b"hello").for_each_chunk(|chunk| seen.push(chunk.to_vec()));
1657        assert_eq!(seen, vec![b"hello".to_vec()]);
1658
1659        let mut count = 0;
1660        IoBufs::default().for_each_chunk(|_| count += 1);
1661        assert_eq!(count, 0);
1662    }
1663
1664    #[test]
1665    fn test_iobufs_shapes_and_read_paths() {
1666        // Empty construction normalizes to an empty single chunk.
1667        let empty = IoBufs::from(Vec::<u8>::new());
1668        assert!(empty.is_empty());
1669        assert!(empty.is_single());
1670        assert!(empty.as_single().is_some());
1671
1672        // Single-buffer read path.
1673        let mut single = IoBufs::from(b"hello world");
1674        assert!(single.is_single());
1675        assert_eq!(single.chunk(), b"hello world");
1676        single.advance(6);
1677        assert_eq!(single.chunk(), b"world");
1678        assert_eq!(single.copy_to_bytes(5).as_ref(), b"world");
1679        assert_eq!(single.remaining(), 0);
1680
1681        // Fast-path shapes (Pair/Triple/Chunked).
1682        let mut pair = IoBufs::from(IoBuf::from(b"a"));
1683        pair.append(IoBuf::from(b"b"));
1684        assert!(matches!(pair.inner, IoBufsInner::Pair(_)));
1685        assert!(pair.as_single().is_none());
1686
1687        let mut triple = IoBufs::from(IoBuf::from(b"a"));
1688        triple.append(IoBuf::from(b"b"));
1689        triple.append(IoBuf::from(b"c"));
1690        assert!(matches!(triple.inner, IoBufsInner::Triple(_)));
1691
1692        let mut chunked = IoBufs::from(IoBuf::from(b"a"));
1693        chunked.append(IoBuf::from(b"b"));
1694        chunked.append(IoBuf::from(b"c"));
1695        chunked.append(IoBuf::from(b"d"));
1696        assert!(matches!(chunked.inner, IoBufsInner::Chunked(_)));
1697
1698        // prepend + append preserve ordering.
1699        let mut joined = IoBufs::from(b"middle");
1700        joined.prepend(IoBuf::from(b"start "));
1701        joined.append(IoBuf::from(b" end"));
1702        assert_eq!(joined.coalesce(), b"start middle end");
1703
1704        // prepending empty is a no-op, and prepending into pair upgrades to triple.
1705        let mut prepend_noop = IoBufs::from(b"x");
1706        prepend_noop.prepend(IoBuf::default());
1707        assert_eq!(prepend_noop.coalesce(), b"x");
1708
1709        // Prepending into an empty aggregate should stay on the single-buffer fast path.
1710        let mut prepend_into_empty = IoBufs::default();
1711        prepend_into_empty.prepend(IoBuf::from(b"z"));
1712        assert!(prepend_into_empty.is_single());
1713        assert_eq!(prepend_into_empty.coalesce(), b"z");
1714
1715        let mut prepend_pair = IoBufs::from(vec![IoBuf::from(b"b"), IoBuf::from(b"c")]);
1716        prepend_pair.prepend(IoBuf::from(b"a"));
1717        assert!(matches!(prepend_pair.inner, IoBufsInner::Triple(_)));
1718        assert_eq!(prepend_pair.coalesce(), b"abc");
1719
1720        // canonicalizing a non-empty single should keep the same representation.
1721        let mut canonical_single = IoBufs::from(b"q");
1722        canonical_single.canonicalize();
1723        assert!(canonical_single.is_single());
1724        assert_eq!(canonical_single.coalesce(), b"q");
1725    }
1726
1727    #[test]
1728    fn test_iobufs_split_to_cases() {
1729        // Zero and full split on a single chunk.
1730        let mut bufs = IoBufs::from(b"hello");
1731
1732        let empty = bufs.split_to(0);
1733        assert!(empty.is_empty());
1734        assert_eq!(bufs.coalesce(), b"hello");
1735
1736        let mut bufs = IoBufs::from(b"hello");
1737        let all = bufs.split_to(5);
1738        assert_eq!(all.coalesce(), b"hello");
1739        assert!(bufs.is_single());
1740        assert!(bufs.is_empty());
1741
1742        // Single split in the middle.
1743        let mut single_mid = IoBufs::from(b"hello");
1744        let single_prefix = single_mid.split_to(2);
1745        assert!(single_prefix.is_single());
1746        assert_eq!(single_prefix.coalesce(), b"he");
1747        assert_eq!(single_mid.coalesce(), b"llo");
1748
1749        // Pair split paths: in-first, boundary-after-first, crossing-into-second.
1750        let mut pair = IoBufs::from(vec![IoBuf::from(b"ab"), IoBuf::from(b"cd")]);
1751        let pair_prefix = pair.split_to(1);
1752        assert!(pair_prefix.is_single());
1753        assert_eq!(pair_prefix.coalesce(), b"a");
1754        assert!(matches!(pair.inner, IoBufsInner::Pair(_)));
1755        assert_eq!(pair.coalesce(), b"bcd");
1756
1757        let mut pair = IoBufs::from(vec![IoBuf::from(b"ab"), IoBuf::from(b"cd")]);
1758        let pair_prefix = pair.split_to(2);
1759        assert!(pair_prefix.is_single());
1760        assert_eq!(pair_prefix.coalesce(), b"ab");
1761        assert!(pair.is_single());
1762        assert_eq!(pair.coalesce(), b"cd");
1763
1764        let mut pair = IoBufs::from(vec![IoBuf::from(b"ab"), IoBuf::from(b"cd")]);
1765        let pair_prefix = pair.split_to(3);
1766        assert!(matches!(pair_prefix.inner, IoBufsInner::Pair(_)));
1767        assert_eq!(pair_prefix.coalesce(), b"abc");
1768        assert!(pair.is_single());
1769        assert_eq!(pair.coalesce(), b"d");
1770
1771        // Triple split paths: in-first, boundary-after-first, in-second, boundary-after-second,
1772        // and reaching into third.
1773        let mut triple = IoBufs::from(vec![
1774            IoBuf::from(b"ab"),
1775            IoBuf::from(b"cd"),
1776            IoBuf::from(b"ef"),
1777        ]);
1778        let triple_prefix = triple.split_to(1);
1779        assert!(triple_prefix.is_single());
1780        assert_eq!(triple_prefix.coalesce(), b"a");
1781        assert!(matches!(triple.inner, IoBufsInner::Triple(_)));
1782        assert_eq!(triple.coalesce(), b"bcdef");
1783
1784        let mut triple = IoBufs::from(vec![
1785            IoBuf::from(b"ab"),
1786            IoBuf::from(b"cd"),
1787            IoBuf::from(b"ef"),
1788        ]);
1789        let triple_prefix = triple.split_to(2);
1790        assert!(triple_prefix.is_single());
1791        assert_eq!(triple_prefix.coalesce(), b"ab");
1792        assert!(matches!(triple.inner, IoBufsInner::Pair(_)));
1793        assert_eq!(triple.coalesce(), b"cdef");
1794
1795        let mut triple = IoBufs::from(vec![
1796            IoBuf::from(b"ab"),
1797            IoBuf::from(b"cd"),
1798            IoBuf::from(b"ef"),
1799        ]);
1800        let triple_prefix = triple.split_to(3);
1801        assert!(matches!(triple_prefix.inner, IoBufsInner::Pair(_)));
1802        assert_eq!(triple_prefix.coalesce(), b"abc");
1803        assert!(matches!(triple.inner, IoBufsInner::Pair(_)));
1804        assert_eq!(triple.coalesce(), b"def");
1805
1806        let mut triple = IoBufs::from(vec![
1807            IoBuf::from(b"ab"),
1808            IoBuf::from(b"cd"),
1809            IoBuf::from(b"ef"),
1810        ]);
1811        let triple_prefix = triple.split_to(4);
1812        assert!(matches!(triple_prefix.inner, IoBufsInner::Pair(_)));
1813        assert_eq!(triple_prefix.coalesce(), b"abcd");
1814        assert!(triple.is_single());
1815        assert_eq!(triple.coalesce(), b"ef");
1816
1817        let mut triple = IoBufs::from(vec![
1818            IoBuf::from(b"ab"),
1819            IoBuf::from(b"cd"),
1820            IoBuf::from(b"ef"),
1821        ]);
1822        let triple_prefix = triple.split_to(5);
1823        assert!(matches!(triple_prefix.inner, IoBufsInner::Triple(_)));
1824        assert_eq!(triple_prefix.coalesce(), b"abcde");
1825        assert!(triple.is_single());
1826        assert_eq!(triple.coalesce(), b"f");
1827
1828        // Chunked split can canonicalize remainder/prefix shapes.
1829        let mut bufs = IoBufs::from(vec![
1830            IoBuf::from(b"ab"),
1831            IoBuf::from(b"cd"),
1832            IoBuf::from(b"ef"),
1833            IoBuf::from(b"gh"),
1834        ]);
1835        let prefix = bufs.split_to(4);
1836        assert!(matches!(prefix.inner, IoBufsInner::Pair(_)));
1837        assert_eq!(prefix.coalesce(), b"abcd");
1838        assert!(matches!(bufs.inner, IoBufsInner::Pair(_)));
1839        assert_eq!(bufs.coalesce(), b"efgh");
1840
1841        // Chunked split inside a chunk.
1842        let mut bufs = IoBufs::from(vec![
1843            IoBuf::from(b"ab"),
1844            IoBuf::from(b"cd"),
1845            IoBuf::from(b"ef"),
1846            IoBuf::from(b"gh"),
1847        ]);
1848        let prefix = bufs.split_to(5);
1849        assert!(matches!(prefix.inner, IoBufsInner::Triple(_)));
1850        assert_eq!(prefix.coalesce(), b"abcde");
1851        assert!(matches!(bufs.inner, IoBufsInner::Pair(_)));
1852        assert_eq!(bufs.coalesce(), b"fgh");
1853
1854        // Chunked split can remain chunked on both sides when both have >= 4 chunks.
1855        let mut bufs = IoBufs::from(vec![
1856            IoBuf::from(b"a"),
1857            IoBuf::from(b"b"),
1858            IoBuf::from(b"c"),
1859            IoBuf::from(b"d"),
1860            IoBuf::from(b"e"),
1861            IoBuf::from(b"f"),
1862            IoBuf::from(b"g"),
1863            IoBuf::from(b"h"),
1864        ]);
1865        let prefix = bufs.split_to(4);
1866        assert!(matches!(prefix.inner, IoBufsInner::Chunked(_)));
1867        assert_eq!(prefix.coalesce(), b"abcd");
1868        assert!(matches!(bufs.inner, IoBufsInner::Chunked(_)));
1869        assert_eq!(bufs.coalesce(), b"efgh");
1870
1871        // Defensive path: tolerate accidental empty chunks in non-canonical chunked input.
1872        let mut bufs = IoBufs {
1873            inner: IoBufsInner::Chunked(VecDeque::from([
1874                IoBuf::default(),
1875                IoBuf::from(b"ab"),
1876                IoBuf::from(b"cd"),
1877                IoBuf::from(b"ef"),
1878                IoBuf::from(b"gh"),
1879            ])),
1880        };
1881        let prefix = bufs.split_to(3);
1882        assert_eq!(prefix.coalesce(), b"abc");
1883        assert_eq!(bufs.coalesce(), b"defgh");
1884    }
1885
1886    #[test]
1887    #[should_panic(expected = "split_to out of bounds")]
1888    fn test_iobufs_split_to_out_of_bounds() {
1889        let mut bufs = IoBufs::from(b"abc");
1890        let _ = bufs.split_to(4);
1891    }
1892
1893    #[test]
1894    fn test_iobufs_chunk_count() {
1895        assert_eq!(IoBufs::default().chunk_count(), 0);
1896        assert_eq!(IoBufs::from(IoBuf::from(b"a")).chunk_count(), 1);
1897        assert_eq!(
1898            IoBufs::from(vec![IoBuf::from(b"b"), IoBuf::from(b"c")]).chunk_count(),
1899            2
1900        );
1901        assert_eq!(
1902            IoBufs::from(vec![
1903                IoBuf::from(b"a"),
1904                IoBuf::from(b"b"),
1905                IoBuf::from(b"c")
1906            ])
1907            .chunk_count(),
1908            3
1909        );
1910        assert_eq!(
1911            IoBufs::from(vec![
1912                IoBuf::from(b"a"),
1913                IoBuf::from(b"b"),
1914                IoBuf::from(b"c"),
1915                IoBuf::from(b"d")
1916            ])
1917            .chunk_count(),
1918            4
1919        );
1920    }
1921
1922    #[test]
1923    fn test_iobufs_coalesce_after_advance() {
1924        let mut bufs = IoBufs::from(IoBuf::from(b"hello"));
1925        bufs.append(IoBuf::from(b" world"));
1926
1927        assert_eq!(bufs.len(), 11);
1928
1929        bufs.advance(3);
1930        assert_eq!(bufs.len(), 8);
1931
1932        assert_eq!(bufs.coalesce(), b"lo world");
1933    }
1934
1935    #[test]
1936    fn test_iobufs_coalesce_with_pool() {
1937        let pool = test_pool();
1938
1939        // Single buffer: zero-copy (same pointer)
1940        let buf = IoBuf::from(vec![1u8, 2, 3, 4, 5]);
1941        let original_ptr = buf.as_ptr();
1942        let bufs = IoBufs::from(buf);
1943        let coalesced = bufs.coalesce_with_pool(&pool);
1944        assert_eq!(coalesced, [1, 2, 3, 4, 5]);
1945        assert_eq!(coalesced.as_ptr(), original_ptr);
1946
1947        // Multiple buffers: merged using pool
1948        let mut bufs = IoBufs::from(IoBuf::from(b"hello"));
1949        bufs.append(IoBuf::from(b" world"));
1950        let coalesced = bufs.coalesce_with_pool(&pool);
1951        assert_eq!(coalesced, b"hello world");
1952
1953        // Multiple buffers after advance: only remaining data coalesced
1954        let mut bufs = IoBufs::from(IoBuf::from(b"hello"));
1955        bufs.append(IoBuf::from(b" world"));
1956        bufs.advance(3);
1957        let coalesced = bufs.coalesce_with_pool(&pool);
1958        assert_eq!(coalesced, b"lo world");
1959
1960        // Empty buffers in the middle
1961        let mut bufs = IoBufs::from(IoBuf::from(b"hello"));
1962        bufs.append(IoBuf::default());
1963        bufs.append(IoBuf::from(b" world"));
1964        let coalesced = bufs.coalesce_with_pool(&pool);
1965        assert_eq!(coalesced, b"hello world");
1966
1967        // Empty IoBufs
1968        let bufs = IoBufs::default();
1969        let coalesced = bufs.coalesce_with_pool(&pool);
1970        assert!(coalesced.is_empty());
1971
1972        // 4+ buffers: exercise chunked coalesce-with-pool path.
1973        let bufs = IoBufs::from(vec![
1974            IoBuf::from(b"ab"),
1975            IoBuf::from(b"cd"),
1976            IoBuf::from(b"ef"),
1977            IoBuf::from(b"gh"),
1978        ]);
1979        let coalesced = bufs.coalesce_with_pool(&pool);
1980        assert_eq!(coalesced, b"abcdefgh");
1981        assert!(coalesced.is_pooled());
1982    }
1983
1984    #[test]
1985    fn test_iobufs_empty_chunks_and_copy_to_bytes_paths() {
1986        // Empty chunks are skipped while reading across multiple chunks.
1987        let mut bufs = IoBufs::default();
1988        bufs.append(IoBuf::from(b"hello"));
1989        bufs.append(IoBuf::default());
1990        bufs.append(IoBuf::from(b" "));
1991        bufs.append(IoBuf::default());
1992        bufs.append(IoBuf::from(b"world"));
1993        assert_eq!(bufs.len(), 11);
1994        assert_eq!(bufs.chunk(), b"hello");
1995        bufs.advance(5);
1996        assert_eq!(bufs.chunk(), b" ");
1997        bufs.advance(1);
1998        assert_eq!(bufs.chunk(), b"world");
1999
2000        // Single-buffer copy_to_bytes path.
2001        let mut single = IoBufs::from(b"hello world");
2002        assert_eq!(single.copy_to_bytes(5).as_ref(), b"hello");
2003        assert_eq!(single.remaining(), 6);
2004
2005        // Multi-buffer copy_to_bytes path across boundaries.
2006        let mut multi = IoBufs::from(b"hello");
2007        multi.prepend(IoBuf::from(b"say "));
2008        assert_eq!(multi.copy_to_bytes(7).as_ref(), b"say hel");
2009        assert_eq!(multi.copy_to_bytes(2).as_ref(), b"lo");
2010    }
2011
2012    #[test]
2013    fn test_iobufs_copy_to_bytes_pair_and_triple() {
2014        // Pair: crossing one boundary should collapse to the trailing single chunk.
2015        let mut pair = IoBufs::from(IoBuf::from(b"ab"));
2016        pair.append(IoBuf::from(b"cd"));
2017        let first = pair.copy_to_bytes(3);
2018        assert_eq!(&first[..], b"abc");
2019        assert!(pair.is_single());
2020        assert_eq!(pair.chunk(), b"d");
2021
2022        // Triple: draining across two chunks leaves the final chunk readable.
2023        let mut triple = IoBufs::from(IoBuf::from(b"ab"));
2024        triple.append(IoBuf::from(b"cd"));
2025        triple.append(IoBuf::from(b"ef"));
2026        let first = triple.copy_to_bytes(5);
2027        assert_eq!(&first[..], b"abcde");
2028        assert!(triple.is_single());
2029        assert_eq!(triple.chunk(), b"f");
2030    }
2031
2032    #[test]
2033    fn test_iobufs_copy_to_bytes_chunked_four_plus() {
2034        let mut bufs = IoBufs::from(vec![
2035            IoBuf::from(b"ab"),
2036            IoBuf::from(b"cd"),
2037            IoBuf::from(b"ef"),
2038            IoBuf::from(b"gh"),
2039        ]);
2040
2041        // Chunked fast-path: first chunk alone satisfies request.
2042        let first = bufs.copy_to_bytes(1);
2043        assert_eq!(&first[..], b"a");
2044
2045        // Chunked slow-path: request crosses chunk boundaries.
2046        let second = bufs.copy_to_bytes(4);
2047        assert_eq!(&second[..], b"bcde");
2048
2049        let rest = bufs.copy_to_bytes(3);
2050        assert_eq!(&rest[..], b"fgh");
2051        assert_eq!(bufs.remaining(), 0);
2052    }
2053
2054    #[test]
2055    fn test_iobufs_copy_to_bytes_edge_cases() {
2056        // A non-canonical leading empty chunk in the deque path is popped
2057        // without affecting the copied payload. Canonical construction never
2058        // stores empties, so the state is built directly.
2059        let mut iobufs = IoBufs {
2060            inner: IoBufsInner::Chunked(VecDeque::from([
2061                IoBuf::default(),
2062                IoBuf::from(b"hel"),
2063                IoBuf::from(b"lo"),
2064                IoBuf::from(b" world"),
2065            ])),
2066        };
2067        assert_eq!(iobufs.copy_to_bytes(5).as_ref(), b"hello");
2068        assert_eq!(iobufs.remaining(), 6);
2069
2070        // Boundary-aligned reads should return exact chunk payloads in-order.
2071        let mut boundary = IoBufs::from(IoBuf::from(b"hello"));
2072        boundary.append(IoBuf::from(b"world"));
2073        assert_eq!(boundary.copy_to_bytes(5).as_ref(), b"hello");
2074        assert_eq!(boundary.copy_to_bytes(5).as_ref(), b"world");
2075        assert_eq!(boundary.remaining(), 0);
2076    }
2077
2078    #[test]
2079    #[should_panic(expected = "cannot advance past end of buffer")]
2080    fn test_iobufs_advance_past_end() {
2081        let mut bufs = IoBufs::from(b"hel");
2082        bufs.append(IoBuf::from(b"lo"));
2083        bufs.advance(10);
2084    }
2085
2086    #[test]
2087    #[should_panic(expected = "not enough data")]
2088    fn test_iobufs_copy_to_bytes_past_end() {
2089        let mut bufs = IoBufs::from(b"hel");
2090        bufs.append(IoBuf::from(b"lo"));
2091        bufs.copy_to_bytes(10);
2092    }
2093
2094    #[test]
2095    fn test_iobufs_matches_bytes_chain() {
2096        let b1 = Bytes::from_static(b"hello");
2097        let b2 = Bytes::from_static(b" ");
2098        let b3 = Bytes::from_static(b"world");
2099
2100        // Buf parity for remaining/chunk/advance should match `Bytes::chain`.
2101        let mut chain = b1.clone().chain(b2.clone()).chain(b3.clone());
2102        let mut iobufs = IoBufs::from(IoBuf::from(b1.clone()));
2103        iobufs.append(IoBuf::from(b2.clone()));
2104        iobufs.append(IoBuf::from(b3.clone()));
2105
2106        assert_eq!(chain.remaining(), iobufs.remaining());
2107        assert_eq!(chain.chunk(), iobufs.chunk());
2108
2109        chain.advance(3);
2110        iobufs.advance(3);
2111        assert_eq!(chain.remaining(), iobufs.remaining());
2112        assert_eq!(chain.chunk(), iobufs.chunk());
2113
2114        chain.advance(3);
2115        iobufs.advance(3);
2116        assert_eq!(chain.remaining(), iobufs.remaining());
2117        assert_eq!(chain.chunk(), iobufs.chunk());
2118
2119        // Test copy_to_bytes
2120        let mut chain = b1.clone().chain(b2.clone()).chain(b3.clone());
2121        let mut iobufs = IoBufs::from(IoBuf::from(b1));
2122        iobufs.append(IoBuf::from(b2));
2123        iobufs.append(IoBuf::from(b3));
2124
2125        assert_eq!(chain.copy_to_bytes(3), iobufs.copy_to_bytes(3));
2126        assert_eq!(chain.copy_to_bytes(4), iobufs.copy_to_bytes(4));
2127        assert_eq!(
2128            chain.copy_to_bytes(chain.remaining()),
2129            iobufs.copy_to_bytes(iobufs.remaining())
2130        );
2131        assert_eq!(chain.remaining(), 0);
2132        assert_eq!(iobufs.remaining(), 0);
2133    }
2134
2135    #[test]
2136    fn test_iobufs_try_into_single() {
2137        let single = IoBufs::from(IoBuf::from(b"hello"));
2138        let single = single.try_into_single().expect("single expected");
2139        assert_eq!(single, b"hello");
2140
2141        let multi = IoBufs::from(vec![IoBuf::from(b"ab"), IoBuf::from(b"cd")]);
2142        let multi = multi.try_into_single().expect_err("multi expected");
2143        assert_eq!(multi.coalesce(), b"abcd");
2144    }
2145
2146    #[test]
2147    fn test_iobufs_chunks_vectored_multiple_slices() {
2148        // Single non-empty buffers should export exactly one slice.
2149        let single = IoBufs::from(IoBuf::from(b"xy"));
2150        let mut single_dst = [IoSlice::new(&[]); 2];
2151        let count = single.chunks_vectored(&mut single_dst);
2152        assert_eq!(count, 1);
2153        assert_eq!(&single_dst[0][..], b"xy");
2154
2155        // Single empty buffers should export no slices.
2156        let empty_single = IoBufs::default();
2157        let mut empty_single_dst = [IoSlice::new(&[]); 1];
2158        assert_eq!(empty_single.chunks_vectored(&mut empty_single_dst), 0);
2159
2160        let bufs = IoBufs::from(vec![
2161            IoBuf::from(b"ab"),
2162            IoBuf::from(b"cd"),
2163            IoBuf::from(b"ef"),
2164            IoBuf::from(b"gh"),
2165        ]);
2166
2167        // Destination capacity should cap how many chunks we export.
2168        let mut small = [IoSlice::new(&[]); 2];
2169        let count = bufs.chunks_vectored(&mut small);
2170        assert_eq!(count, 2);
2171        assert_eq!(&small[0][..], b"ab");
2172        assert_eq!(&small[1][..], b"cd");
2173
2174        // Larger destination should include every readable chunk.
2175        let mut large = [IoSlice::new(&[]); 8];
2176        let count = bufs.chunks_vectored(&mut large);
2177        assert_eq!(count, 4);
2178        assert_eq!(&large[0][..], b"ab");
2179        assert_eq!(&large[1][..], b"cd");
2180        assert_eq!(&large[2][..], b"ef");
2181        assert_eq!(&large[3][..], b"gh");
2182
2183        // Empty destination cannot accept any slices.
2184        let mut empty_dst: [IoSlice<'_>; 0] = [];
2185        assert_eq!(bufs.chunks_vectored(&mut empty_dst), 0);
2186
2187        // Non-canonical shapes should skip empty leading chunks.
2188        let sparse = IoBufs {
2189            inner: IoBufsInner::Pair([IoBuf::default(), IoBuf::from(b"x")]),
2190        };
2191        let mut dst = [IoSlice::new(&[]); 2];
2192        let count = sparse.chunks_vectored(&mut dst);
2193        assert_eq!(count, 1);
2194        assert_eq!(&dst[0][..], b"x");
2195
2196        // Triple should skip empty chunks and preserve readable order.
2197        let sparse_triple = IoBufs {
2198            inner: IoBufsInner::Triple([IoBuf::default(), IoBuf::from(b"y"), IoBuf::from(b"z")]),
2199        };
2200        let mut dst = [IoSlice::new(&[]); 3];
2201        let count = sparse_triple.chunks_vectored(&mut dst);
2202        assert_eq!(count, 2);
2203        assert_eq!(&dst[0][..], b"y");
2204        assert_eq!(&dst[1][..], b"z");
2205
2206        // Chunked shapes with only empty buffers should export no slices.
2207        let empty_chunked = IoBufs {
2208            inner: IoBufsInner::Chunked(VecDeque::from([IoBuf::default(), IoBuf::default()])),
2209        };
2210        let mut dst = [IoSlice::new(&[]); 2];
2211        assert_eq!(empty_chunked.chunks_vectored(&mut dst), 0);
2212    }
2213
2214    #[test]
2215    fn test_iobufsmut_freeze_chunked() {
2216        // Multiple non-empty buffers stay multi-chunk.
2217        let buf1 = IoBufMut::from(b"hello".as_ref());
2218        let buf2 = IoBufMut::from(b" world".as_ref());
2219        let bufs = IoBufsMut::from(vec![buf1, buf2]);
2220        let mut frozen = bufs.freeze();
2221        assert!(!frozen.is_single());
2222        assert_eq!(frozen.chunk(), b"hello");
2223        frozen.advance(5);
2224        assert_eq!(frozen.chunk(), b" world");
2225        frozen.advance(6);
2226        assert_eq!(frozen.remaining(), 0);
2227
2228        // Empty buffers are filtered out.
2229        let buf1 = IoBufMut::from(b"hello".as_ref());
2230        let empty = IoBufMut::default();
2231        let buf2 = IoBufMut::from(b" world".as_ref());
2232        let bufs = IoBufsMut::from(vec![buf1, empty, buf2]);
2233        let mut frozen = bufs.freeze();
2234        assert!(!frozen.is_single());
2235        assert_eq!(frozen.chunk(), b"hello");
2236        frozen.advance(5);
2237        assert_eq!(frozen.chunk(), b" world");
2238        frozen.advance(6);
2239        assert_eq!(frozen.remaining(), 0);
2240
2241        // Collapses to Single when one non-empty buffer remains
2242        let empty1 = IoBufMut::default();
2243        let buf = IoBufMut::from(b"only one".as_ref());
2244        let empty2 = IoBufMut::default();
2245        let bufs = IoBufsMut::from(vec![empty1, buf, empty2]);
2246        let frozen = bufs.freeze();
2247        assert!(frozen.is_single());
2248        assert_eq!(frozen.coalesce(), b"only one");
2249
2250        // All empty buffers -> Single with empty buffer
2251        let empty1 = IoBufMut::default();
2252        let empty2 = IoBufMut::default();
2253        let bufs = IoBufsMut::from(vec![empty1, empty2]);
2254        let frozen = bufs.freeze();
2255        assert!(frozen.is_single());
2256        assert!(frozen.is_empty());
2257    }
2258
2259    #[test]
2260    fn test_iobufsmut_from_vec() {
2261        // Empty Vec becomes Single with empty buffer
2262        let bufs = IoBufsMut::from(Vec::<IoBufMut>::new());
2263        assert!(bufs.is_single());
2264        assert!(bufs.is_empty());
2265
2266        // Vec with one element becomes Single
2267        let buf = IoBufMut::from(b"test");
2268        let bufs = IoBufsMut::from(vec![buf]);
2269        assert!(bufs.is_single());
2270        assert_eq!(bufs.chunk(), b"test");
2271
2272        // Vec with multiple elements becomes multi-chunk.
2273        let buf1 = IoBufMut::from(b"hello");
2274        let buf2 = IoBufMut::from(b" world");
2275        let bufs = IoBufsMut::from(vec![buf1, buf2]);
2276        assert!(!bufs.is_single());
2277    }
2278
2279    #[test]
2280    fn test_iobufsmut_fast_path_shapes() {
2281        let pair = IoBufsMut::from(vec![IoBufMut::from(b"a"), IoBufMut::from(b"b")]);
2282        assert!(matches!(pair.inner, IoBufsMutInner::Pair(_)));
2283
2284        let triple = IoBufsMut::from(vec![
2285            IoBufMut::from(b"a"),
2286            IoBufMut::from(b"b"),
2287            IoBufMut::from(b"c"),
2288        ]);
2289        assert!(matches!(triple.inner, IoBufsMutInner::Triple(_)));
2290
2291        let chunked = IoBufsMut::from(vec![
2292            IoBufMut::from(b"a"),
2293            IoBufMut::from(b"b"),
2294            IoBufMut::from(b"c"),
2295            IoBufMut::from(b"d"),
2296        ]);
2297        assert!(matches!(chunked.inner, IoBufsMutInner::Chunked(_)));
2298    }
2299
2300    #[test]
2301    fn test_iobufsmut_default() {
2302        // Default IoBufsMut should be a single empty chunk.
2303        let bufs = IoBufsMut::default();
2304        assert!(bufs.is_single());
2305        assert!(bufs.is_empty());
2306        assert_eq!(bufs.len(), 0);
2307    }
2308
2309    #[test]
2310    fn test_iobufsmut_from_array() {
2311        // From<[u8; N]> should create a single-chunk container with the array data.
2312        let bufs = IoBufsMut::from([1u8, 2, 3, 4, 5]);
2313        assert!(bufs.is_single());
2314        assert_eq!(bufs.len(), 5);
2315        assert_eq!(bufs.chunk(), &[1, 2, 3, 4, 5]);
2316    }
2317
2318    #[test]
2319    fn test_iobufsmut_buf_trait_chunked() {
2320        let buf1 = IoBufMut::from(b"hello");
2321        let buf2 = IoBufMut::from(b" ");
2322        let buf3 = IoBufMut::from(b"world");
2323        let mut bufs = IoBufsMut::from(vec![buf1, buf2, buf3]);
2324
2325        assert_eq!(bufs.remaining(), 11);
2326        assert_eq!(bufs.chunk(), b"hello");
2327
2328        // Advance within first buffer
2329        bufs.advance(3);
2330        assert_eq!(bufs.remaining(), 8);
2331        assert_eq!(bufs.chunk(), b"lo");
2332
2333        // Advance past first buffer (should pop_front)
2334        bufs.advance(2);
2335        assert_eq!(bufs.remaining(), 6);
2336        assert_eq!(bufs.chunk(), b" ");
2337
2338        // Advance exactly one buffer
2339        bufs.advance(1);
2340        assert_eq!(bufs.remaining(), 5);
2341        assert_eq!(bufs.chunk(), b"world");
2342
2343        // Advance to end
2344        bufs.advance(5);
2345        assert_eq!(bufs.remaining(), 0);
2346    }
2347
2348    #[test]
2349    #[should_panic(expected = "cannot advance past end of buffer")]
2350    fn test_iobufsmut_advance_past_end() {
2351        let buf1 = IoBufMut::from(b"hello");
2352        let buf2 = IoBufMut::from(b" world");
2353        let mut bufs = IoBufsMut::from(vec![buf1, buf2]);
2354        bufs.advance(20);
2355    }
2356
2357    #[test]
2358    fn test_iobufsmut_bufmut_trait_single() {
2359        let mut bufs = IoBufsMut::from(IoBufMut::with_capacity(20));
2360        assert_eq!(bufs.remaining_mut(), 20);
2361
2362        bufs.put_slice(b"hello");
2363        assert_eq!(bufs.chunk(), b"hello");
2364        assert_eq!(bufs.len(), 5);
2365        assert_eq!(bufs.remaining_mut(), 15);
2366
2367        bufs.put_slice(b" world");
2368        assert_eq!(bufs.coalesce(), b"hello world");
2369    }
2370
2371    #[test]
2372    fn test_iobufsmut_zeroed_write() {
2373        // Use zeroed buffers which have a fixed length
2374        let bufs = IoBufsMut::from(IoBufMut::zeroed(20));
2375        assert_eq!(bufs.len(), 20);
2376
2377        // Can write using as_mut on coalesced buffer
2378        let mut coalesced = bufs.coalesce();
2379        coalesced.as_mut()[..5].copy_from_slice(b"hello");
2380        assert_eq!(&coalesced.as_ref()[..5], b"hello");
2381    }
2382
2383    #[test]
2384    fn test_iobufsmut_bufmut_put_slice() {
2385        // Test writing across multiple buffers
2386        let buf1 = IoBufMut::with_capacity(5);
2387        let buf2 = IoBufMut::with_capacity(6);
2388        let mut bufs = IoBufsMut::from(vec![buf1, buf2]);
2389
2390        // Write data
2391        bufs.put_slice(b"hello");
2392        bufs.put_slice(b" world");
2393        assert_eq!(bufs.coalesce(), b"hello world");
2394    }
2395
2396    #[test]
2397    fn test_iobufs_advance_drains_buffers() {
2398        let mut bufs = IoBufs::from(IoBuf::from(b"hello"));
2399        bufs.append(IoBuf::from(b" "));
2400        bufs.append(IoBuf::from(b"world"));
2401
2402        // Advance exactly past first buffer
2403        bufs.advance(5);
2404        assert_eq!(bufs.remaining(), 6);
2405        assert_eq!(bufs.chunk(), b" ");
2406
2407        // Advance across multiple buffers
2408        bufs.advance(4);
2409        assert_eq!(bufs.remaining(), 2);
2410        assert_eq!(bufs.chunk(), b"ld");
2411    }
2412
2413    #[test]
2414    fn test_iobufs_advance_exactly_to_boundary() {
2415        let mut bufs = IoBufs::from(IoBuf::from(b"abc"));
2416        bufs.append(IoBuf::from(b"def"));
2417
2418        // Advance exactly to first buffer boundary
2419        bufs.advance(3);
2420        assert_eq!(bufs.remaining(), 3);
2421        assert_eq!(bufs.chunk(), b"def");
2422
2423        // Advance exactly to end
2424        bufs.advance(3);
2425        assert_eq!(bufs.remaining(), 0);
2426    }
2427
2428    #[test]
2429    fn test_iobufs_advance_canonicalizes_pair_to_single() {
2430        let mut bufs = IoBufs::from(IoBuf::from(b"ab"));
2431        bufs.append(IoBuf::from(b"cd"));
2432        bufs.advance(2);
2433        assert!(bufs.is_single());
2434        assert_eq!(bufs.chunk(), b"cd");
2435    }
2436
2437    #[test]
2438    fn test_iobufsmut_with_empty_buffers() {
2439        let buf1 = IoBufMut::from(b"hello");
2440        let buf2 = IoBufMut::default();
2441        let buf3 = IoBufMut::from(b" world");
2442        let mut bufs = IoBufsMut::from(vec![buf1, buf2, buf3]);
2443
2444        assert_eq!(bufs.remaining(), 11);
2445        assert_eq!(bufs.chunk(), b"hello");
2446
2447        // Advance past first buffer
2448        bufs.advance(5);
2449        // Empty buffer should be skipped
2450        assert_eq!(bufs.chunk(), b" world");
2451        assert_eq!(bufs.remaining(), 6);
2452    }
2453
2454    #[test]
2455    fn test_iobufsmut_advance_skips_leading_writable_empty_chunk() {
2456        // A leading chunk with capacity but no readable bytes (len == 0) should
2457        // be skipped during advance, reaching the next readable chunk.
2458        let empty_writable = IoBufMut::with_capacity(4);
2459        let payload = IoBufMut::from(b"xy");
2460        let mut bufs = IoBufsMut::from(vec![empty_writable, payload]);
2461
2462        bufs.advance(1);
2463        assert_eq!(bufs.chunk(), b"y");
2464        assert_eq!(bufs.remaining(), 1);
2465    }
2466
2467    #[test]
2468    fn test_iobufsmut_read_ops_preserve_writable_capacity() {
2469        // Draining the filled first chunk must not discard the never-filled
2470        // second chunk's reserved capacity: remaining_mut only changes via
2471        // advance_mut per the BufMut contract.
2472        let mut a = IoBufMut::with_capacity(8);
2473        a.put_slice(&[1u8; 8]);
2474        let b = IoBufMut::with_capacity(8);
2475        let mut bufs = IoBufsMut::from(vec![a, b]);
2476        assert_eq!(bufs.remaining(), 8);
2477        assert_eq!(bufs.remaining_mut(), 8);
2478        bufs.advance(8);
2479        assert_eq!(bufs.remaining(), 0);
2480        assert_eq!(bufs.remaining_mut(), 8);
2481        bufs.put_slice(&[2u8; 8]);
2482        assert_eq!(bufs.copy_to_bytes(8).as_ref(), &[2u8; 8]);
2483
2484        // copy_to_bytes drains must preserve capacity the same way.
2485        let mut a = IoBufMut::with_capacity(8);
2486        a.put_slice(&[3u8; 8]);
2487        let b = IoBufMut::with_capacity(8);
2488        let mut bufs = IoBufsMut::from(vec![a, b]);
2489        assert_eq!(bufs.copy_to_bytes(8).as_ref(), &[3u8; 8]);
2490        assert_eq!(bufs.remaining_mut(), 8);
2491
2492        // Zero-length drains do not disturb chunk state at all.
2493        assert!(bufs.copy_to_bytes(0).is_empty());
2494        assert_eq!(bufs.remaining_mut(), 8);
2495    }
2496
2497    #[test]
2498    fn test_iobufsmut_from_vec_u8_preserves_capacity() {
2499        // The readable bytes are copied and the vec's reserved capacity is
2500        // preserved exactly.
2501        let mut vec = Vec::with_capacity(128);
2502        vec.extend_from_slice(b"abc");
2503        let cap = vec.capacity();
2504        let mut bufs = IoBufsMut::from(vec);
2505        assert_eq!(bufs.remaining(), 3);
2506        assert_eq!(bufs.capacity(), cap);
2507        bufs.put_slice(b"d");
2508        assert_eq!(bufs.copy_to_bytes(4).as_ref(), b"abcd");
2509
2510        // Empty vec with reserved capacity keeps the full reservation, so
2511        // the documented Vec::with_capacity(len) -> read_at_buf(len) reuse
2512        // pattern holds: set_len(len) must fit.
2513        let vec = Vec::<u8>::with_capacity(64);
2514        let len = vec.capacity();
2515        let mut bufs = IoBufsMut::from(vec);
2516        assert!(bufs.is_empty());
2517        assert_eq!(bufs.capacity(), len);
2518        // SAFETY: all `len` bytes are initialized by copy_from_slice below.
2519        unsafe { bufs.set_len(len) };
2520        bufs.copy_from_slice(&vec![9u8; len]);
2521        assert_eq!(bufs.copy_to_bytes(len).as_ref(), vec![9u8; len].as_slice());
2522
2523        // Exactly-sized vec: copied with contents intact.
2524        let bufs = IoBufsMut::from(vec![1u8, 2, 3]);
2525        assert_eq!(bufs.remaining(), 3);
2526        assert_eq!(bufs.capacity(), 3);
2527        assert_eq!(bufs.chunk(), &[1, 2, 3]);
2528    }
2529
2530    #[test]
2531    fn test_iobufsmut_coalesce_after_advance() {
2532        // Advance mid-chunk: advance 3 of 11 bytes
2533        let buf1 = IoBufMut::from(b"hello");
2534        let buf2 = IoBufMut::from(b" world");
2535        let mut bufs = IoBufsMut::from(vec![buf1, buf2]);
2536
2537        bufs.advance(3);
2538        assert_eq!(bufs.coalesce(), b"lo world");
2539
2540        // Advance to exact chunk boundary: advance 5 of 11 bytes
2541        let buf1 = IoBufMut::from(b"hello");
2542        let buf2 = IoBufMut::from(b" world");
2543        let mut bufs = IoBufsMut::from(vec![buf1, buf2]);
2544
2545        bufs.advance(5);
2546        assert_eq!(bufs.coalesce(), b" world");
2547    }
2548
2549    #[test]
2550    fn test_iobufsmut_copy_to_bytes() {
2551        let buf1 = IoBufMut::from(b"hello");
2552        let buf2 = IoBufMut::from(b" world");
2553        let mut bufs = IoBufsMut::from(vec![buf1, buf2]);
2554
2555        // First read spans chunks and leaves unread suffix.
2556        let first = bufs.copy_to_bytes(7);
2557        assert_eq!(&first[..], b"hello w");
2558        assert_eq!(bufs.remaining(), 4);
2559
2560        // Second read drains the remainder.
2561        let rest = bufs.copy_to_bytes(4);
2562        assert_eq!(&rest[..], b"orld");
2563        assert_eq!(bufs.remaining(), 0);
2564    }
2565
2566    #[test]
2567    fn test_iobufsmut_copy_to_bytes_chunked_four_plus() {
2568        let mut bufs = IoBufsMut::from(vec![
2569            IoBufMut::from(b"ab"),
2570            IoBufMut::from(b"cd"),
2571            IoBufMut::from(b"ef"),
2572            IoBufMut::from(b"gh"),
2573        ]);
2574
2575        // Exercise chunked advance path before copy_to_bytes.
2576        bufs.advance(1);
2577        assert_eq!(bufs.chunk(), b"b");
2578        bufs.advance(1);
2579        assert_eq!(bufs.chunk(), b"cd");
2580
2581        // Chunked fast-path: first chunk alone satisfies request.
2582        let first = bufs.copy_to_bytes(1);
2583        assert_eq!(&first[..], b"c");
2584
2585        // Chunked slow-path: request crosses chunk boundaries.
2586        let second = bufs.copy_to_bytes(4);
2587        assert_eq!(&second[..], b"defg");
2588
2589        let rest = bufs.copy_to_bytes(1);
2590        assert_eq!(&rest[..], b"h");
2591        assert_eq!(bufs.remaining(), 0);
2592
2593        // Enter copy_to_bytes while still in chunked representation.
2594        let mut bufs = IoBufsMut::from(vec![
2595            IoBufMut::from(b"a"),
2596            IoBufMut::from(b"b"),
2597            IoBufMut::from(b"c"),
2598            IoBufMut::from(b"d"),
2599            IoBufMut::from(b"e"),
2600        ]);
2601        assert!(matches!(bufs.inner, IoBufsMutInner::Chunked(_)));
2602        let first = bufs.copy_to_bytes(1);
2603        assert_eq!(&first[..], b"a");
2604        // Stay chunked while consuming across multiple tiny chunks.
2605        let next = bufs.copy_to_bytes(3);
2606        assert_eq!(&next[..], b"bcd");
2607        assert_eq!(bufs.chunk(), b"e");
2608        assert_eq!(bufs.remaining(), 1);
2609    }
2610
2611    #[test]
2612    fn test_iobufsmut_copy_to_bytes_canonicalizes_pair() {
2613        let mut bufs = IoBufsMut::from(vec![IoBufMut::from(b"ab"), IoBufMut::from(b"cd")]);
2614        assert!(matches!(bufs.inner, IoBufsMutInner::Pair(_)));
2615
2616        let first = bufs.copy_to_bytes(2);
2617        assert_eq!(&first[..], b"ab");
2618
2619        assert!(bufs.is_single());
2620        assert_eq!(bufs.chunk(), b"cd");
2621        assert_eq!(bufs.remaining(), 2);
2622    }
2623
2624    #[test]
2625    fn test_iobufsmut_copy_from_slice_single() {
2626        let mut bufs = IoBufsMut::from(IoBufMut::zeroed(11));
2627        bufs.copy_from_slice(b"hello world");
2628        assert_eq!(bufs.coalesce(), b"hello world");
2629    }
2630
2631    #[test]
2632    fn test_iobufsmut_copy_from_slice_chunked() {
2633        let buf1 = IoBufMut::zeroed(5);
2634        let buf2 = IoBufMut::zeroed(6);
2635        let mut bufs = IoBufsMut::from(vec![buf1, buf2]);
2636
2637        bufs.copy_from_slice(b"hello world");
2638
2639        // Verify each chunk was filled correctly.
2640        assert_eq!(bufs.chunk(), b"hello");
2641        bufs.advance(5);
2642        assert_eq!(bufs.chunk(), b" world");
2643        bufs.advance(6);
2644        assert_eq!(bufs.remaining(), 0);
2645    }
2646
2647    #[test]
2648    #[should_panic(expected = "source slice length must match buffer length")]
2649    fn test_iobufsmut_copy_from_slice_wrong_length() {
2650        let mut bufs = IoBufsMut::from(IoBufMut::zeroed(5));
2651        bufs.copy_from_slice(b"hello world"); // 11 bytes into 5-byte buffer
2652    }
2653
2654    #[test]
2655    fn test_iobufsmut_matches_bytesmut_chain() {
2656        // Create three BytesMut with capacity for final content comparison.
2657        let mut bm1 = BytesMut::with_capacity(5);
2658        let mut bm2 = BytesMut::with_capacity(6);
2659        let mut bm3 = BytesMut::with_capacity(7);
2660
2661        // Create matching IoBufsMut
2662        let mut iobufs = IoBufsMut::from(vec![
2663            IoBufMut::with_capacity(5),
2664            IoBufMut::with_capacity(6),
2665            IoBufMut::with_capacity(7),
2666        ]);
2667
2668        // Fixed-capacity IoBufsMut exposes the current writable chunk.
2669        assert_eq!(iobufs.chunk_mut().len(), 5);
2670
2671        // Write some data
2672        (&mut bm1)
2673            .chain_mut(&mut bm2)
2674            .chain_mut(&mut bm3)
2675            .put_slice(b"hel");
2676        iobufs.put_slice(b"hel");
2677
2678        assert_eq!(iobufs.chunk_mut().len(), 2);
2679
2680        // Write more data
2681        (&mut bm1)
2682            .chain_mut(&mut bm2)
2683            .chain_mut(&mut bm3)
2684            .put_slice(b"lo world!");
2685        iobufs.put_slice(b"lo world!");
2686
2687        assert_eq!(iobufs.chunk_mut().len(), 6);
2688
2689        // Verify final content matches
2690        let frozen = iobufs.freeze().coalesce();
2691        let mut chain_content = bm1.to_vec();
2692        chain_content.extend_from_slice(&bm2);
2693        chain_content.extend_from_slice(&bm3);
2694        assert_eq!(frozen, chain_content.as_slice());
2695        assert_eq!(frozen, b"hello world!");
2696    }
2697
2698    #[test]
2699    fn test_iobufsmut_buf_matches_bytes_chain() {
2700        // Create pre-filled Bytes buffers
2701        let mut b1 = Bytes::from_static(b"hello");
2702        let mut b2 = Bytes::from_static(b" world");
2703        let b3 = Bytes::from_static(b"!");
2704
2705        // Create matching IoBufsMut
2706        let mut iobufs = IoBufsMut::from(vec![
2707            IoBufMut::from(b"hello"),
2708            IoBufMut::from(b" world"),
2709            IoBufMut::from(b"!"),
2710        ]);
2711
2712        // Test Buf::remaining matches
2713        let chain_remaining = b1.clone().chain(b2.clone()).chain(b3.clone()).remaining();
2714        assert_eq!(chain_remaining, iobufs.remaining());
2715
2716        // Test Buf::chunk matches
2717        let chain_chunk = b1
2718            .clone()
2719            .chain(b2.clone())
2720            .chain(b3.clone())
2721            .chunk()
2722            .to_vec();
2723        assert_eq!(chain_chunk, iobufs.chunk().to_vec());
2724
2725        // Advance and test again
2726        b1.advance(3);
2727        iobufs.advance(3);
2728
2729        let chain_remaining = b1.clone().chain(b2.clone()).chain(b3.clone()).remaining();
2730        assert_eq!(chain_remaining, iobufs.remaining());
2731
2732        let chain_chunk = b1
2733            .clone()
2734            .chain(b2.clone())
2735            .chain(b3.clone())
2736            .chunk()
2737            .to_vec();
2738        assert_eq!(chain_chunk, iobufs.chunk().to_vec());
2739
2740        // Advance past first buffer boundary into second
2741        b1.advance(2);
2742        iobufs.advance(2);
2743
2744        let chain_remaining = b1.clone().chain(b2.clone()).chain(b3.clone()).remaining();
2745        assert_eq!(chain_remaining, iobufs.remaining());
2746
2747        // Now we should be in the second buffer
2748        let chain_chunk = b1
2749            .clone()
2750            .chain(b2.clone())
2751            .chain(b3.clone())
2752            .chunk()
2753            .to_vec();
2754        assert_eq!(chain_chunk, iobufs.chunk().to_vec());
2755
2756        // Advance past second buffer boundary into third
2757        b2.advance(6);
2758        iobufs.advance(6);
2759
2760        let chain_remaining = b1.clone().chain(b2.clone()).chain(b3.clone()).remaining();
2761        assert_eq!(chain_remaining, iobufs.remaining());
2762
2763        // Now we should be in the third buffer
2764        let chain_chunk = b1.chain(b2).chain(b3).chunk().to_vec();
2765        assert_eq!(chain_chunk, iobufs.chunk().to_vec());
2766
2767        // Test copy_to_bytes
2768        let b1 = Bytes::from_static(b"hello");
2769        let b2 = Bytes::from_static(b" world");
2770        let b3 = Bytes::from_static(b"!");
2771        let mut iobufs = IoBufsMut::from(vec![
2772            IoBufMut::from(b"hello"),
2773            IoBufMut::from(b" world"),
2774            IoBufMut::from(b"!"),
2775        ]);
2776
2777        let chain_bytes = b1.chain(b2).chain(b3).copy_to_bytes(8);
2778        let iobufs_bytes = iobufs.copy_to_bytes(8);
2779        assert_eq!(chain_bytes, iobufs_bytes);
2780        assert_eq!(chain_bytes.as_ref(), b"hello wo");
2781    }
2782
2783    #[test]
2784    fn test_iobufsmut_chunks_vectored_multiple_slices() {
2785        // Single non-empty buffers should export exactly one slice.
2786        let single = IoBufsMut::from(IoBufMut::from(b"xy"));
2787        let mut single_dst = [IoSlice::new(&[]); 2];
2788        let count = single.chunks_vectored(&mut single_dst);
2789        assert_eq!(count, 1);
2790        assert_eq!(&single_dst[0][..], b"xy");
2791
2792        // Single empty buffers should export no slices.
2793        let empty_single = IoBufsMut::default();
2794        let mut empty_single_dst = [IoSlice::new(&[]); 1];
2795        assert_eq!(empty_single.chunks_vectored(&mut empty_single_dst), 0);
2796
2797        let bufs = IoBufsMut::from(vec![
2798            IoBufMut::from(b"ab"),
2799            IoBufMut::from(b"cd"),
2800            IoBufMut::from(b"ef"),
2801            IoBufMut::from(b"gh"),
2802        ]);
2803
2804        // Destination capacity should cap how many chunks we export.
2805        let mut small = [IoSlice::new(&[]); 2];
2806        let count = bufs.chunks_vectored(&mut small);
2807        assert_eq!(count, 2);
2808        assert_eq!(&small[0][..], b"ab");
2809        assert_eq!(&small[1][..], b"cd");
2810
2811        // Larger destination should include every readable chunk.
2812        let mut large = [IoSlice::new(&[]); 8];
2813        let count = bufs.chunks_vectored(&mut large);
2814        assert_eq!(count, 4);
2815        assert_eq!(&large[0][..], b"ab");
2816        assert_eq!(&large[1][..], b"cd");
2817        assert_eq!(&large[2][..], b"ef");
2818        assert_eq!(&large[3][..], b"gh");
2819
2820        // Empty destination cannot accept any slices.
2821        let mut empty_dst: [IoSlice<'_>; 0] = [];
2822        assert_eq!(bufs.chunks_vectored(&mut empty_dst), 0);
2823
2824        // Non-canonical shapes should skip empty leading chunks.
2825        let sparse = IoBufsMut {
2826            inner: IoBufsMutInner::Pair([IoBufMut::default(), IoBufMut::from(b"y")]),
2827        };
2828        let mut dst = [IoSlice::new(&[]); 2];
2829        let count = sparse.chunks_vectored(&mut dst);
2830        assert_eq!(count, 1);
2831        assert_eq!(&dst[0][..], b"y");
2832
2833        // Triple should skip empty chunks and preserve readable order.
2834        let sparse_triple = IoBufsMut {
2835            inner: IoBufsMutInner::Triple([
2836                IoBufMut::default(),
2837                IoBufMut::from(b"z"),
2838                IoBufMut::from(b"w"),
2839            ]),
2840        };
2841        let mut dst = [IoSlice::new(&[]); 3];
2842        let count = sparse_triple.chunks_vectored(&mut dst);
2843        assert_eq!(count, 2);
2844        assert_eq!(&dst[0][..], b"z");
2845        assert_eq!(&dst[1][..], b"w");
2846
2847        // Chunked shapes with only empty buffers should export no slices.
2848        let empty_chunked = IoBufsMut {
2849            inner: IoBufsMutInner::Chunked(VecDeque::from([
2850                IoBufMut::default(),
2851                IoBufMut::default(),
2852            ])),
2853        };
2854        let mut dst = [IoSlice::new(&[]); 2];
2855        assert_eq!(empty_chunked.chunks_vectored(&mut dst), 0);
2856    }
2857
2858    #[test]
2859    fn test_iobufsmut_try_into_single() {
2860        let single = IoBufsMut::from(IoBufMut::from(b"hello"));
2861        let single = single.try_into_single().expect("single expected");
2862        assert_eq!(single, b"hello");
2863
2864        let multi = IoBufsMut::from(vec![IoBufMut::from(b"ab"), IoBufMut::from(b"cd")]);
2865        let multi = multi.try_into_single().expect_err("multi expected");
2866        assert_eq!(multi.coalesce(), b"abcd");
2867    }
2868
2869    #[test]
2870    fn test_iobufsmut_freeze_after_advance() {
2871        // Partial advance: advance 3 of 11 bytes
2872        let buf1 = IoBufMut::from(b"hello");
2873        let buf2 = IoBufMut::from(b" world");
2874        let mut bufs = IoBufsMut::from(vec![buf1, buf2]);
2875
2876        bufs.advance(3);
2877        assert_eq!(bufs.len(), 8);
2878
2879        let frozen = bufs.freeze();
2880        assert_eq!(frozen.len(), 8);
2881        assert_eq!(frozen.coalesce(), b"lo world");
2882
2883        // Exact boundary advance: advance 5 of 11 bytes (first buf is 5 bytes)
2884        let buf1 = IoBufMut::from(b"hello");
2885        let buf2 = IoBufMut::from(b" world");
2886        let mut bufs = IoBufsMut::from(vec![buf1, buf2]);
2887
2888        bufs.advance(5);
2889        assert_eq!(bufs.len(), 6);
2890
2891        // First buffer should be fully consumed (empty after advance)
2892        // freeze() filters empty buffers, so result should be Single
2893        let frozen = bufs.freeze();
2894        assert!(frozen.is_single());
2895        assert_eq!(frozen.coalesce(), b" world");
2896    }
2897
2898    #[test]
2899    fn test_iobufsmut_coalesce_with_pool() {
2900        let pool = test_pool();
2901
2902        // Single buffer: zero-copy (same pointer)
2903        let mut buf = IoBufMut::from(b"hello");
2904        let original_ptr = buf.as_mut_ptr();
2905        let bufs = IoBufsMut::from(buf);
2906        let coalesced = bufs.coalesce_with_pool(&pool);
2907        assert_eq!(coalesced, b"hello");
2908        assert_eq!(coalesced.as_ref().as_ptr(), original_ptr);
2909
2910        // Multiple buffers: merged using pool
2911        let bufs = IoBufsMut::from(vec![IoBufMut::from(b"hello"), IoBufMut::from(b" world")]);
2912        let coalesced = bufs.coalesce_with_pool(&pool);
2913        assert_eq!(coalesced, b"hello world");
2914        assert!(coalesced.is_pooled());
2915
2916        // Four chunks force the deque-backed coalesce path instead of pair/triple fast paths.
2917        let bufs = IoBufsMut::from(vec![
2918            IoBufMut::from(b"a"),
2919            IoBufMut::from(b"b"),
2920            IoBufMut::from(b"c"),
2921            IoBufMut::from(b"d"),
2922        ]);
2923        let coalesced = bufs.coalesce_with_pool(&pool);
2924        assert_eq!(coalesced, b"abcd");
2925        assert!(coalesced.is_pooled());
2926
2927        // With extra capacity: zero-copy if sufficient spare capacity
2928        let mut buf = IoBufMut::with_capacity(100);
2929        buf.put_slice(b"hello");
2930        let original_ptr = buf.as_mut_ptr();
2931        let bufs = IoBufsMut::from(buf);
2932        let coalesced = bufs.coalesce_with_pool_extra(&pool, 10);
2933        assert_eq!(coalesced, b"hello");
2934        assert_eq!(coalesced.as_ref().as_ptr(), original_ptr);
2935
2936        // With extra capacity: reallocates if insufficient
2937        let mut buf = IoBufMut::with_capacity(5);
2938        buf.put_slice(b"hello");
2939        let bufs = IoBufsMut::from(buf);
2940        let coalesced = bufs.coalesce_with_pool_extra(&pool, 100);
2941        assert_eq!(coalesced, b"hello");
2942        assert!(coalesced.capacity() >= 105);
2943    }
2944
2945    #[test]
2946    fn test_iobufs_additional_shape_and_conversion_paths() {
2947        let pool = test_pool();
2948
2949        // Constructor coverage for mutable/immutable/slice-backed inputs.
2950        let from_mut = IoBufs::from(IoBufMut::from(b"m"));
2951        assert_eq!(from_mut.chunk(), b"m");
2952        let from_bytes = IoBufs::from(Bytes::from_static(b"b"));
2953        assert_eq!(from_bytes.chunk(), b"b");
2954        let from_bytesmut = IoBufs::from(BytesMut::from(&b"bm"[..]));
2955        assert_eq!(from_bytesmut.chunk(), b"bm");
2956        let from_vec = IoBufs::from(vec![1u8, 2u8]);
2957        assert_eq!(from_vec.chunk(), &[1u8, 2]);
2958        let static_slice: &'static [u8] = b"slice";
2959        let from_static = IoBufs::from(static_slice);
2960        assert_eq!(from_static.chunk(), b"slice");
2961
2962        // Canonicalizing an already-empty buffer remains a single empty chunk.
2963        let mut single_empty = IoBufs::default();
2964        single_empty.canonicalize();
2965        assert!(single_empty.is_single());
2966
2967        // Triple path: prepend/append can promote into chunked while preserving order.
2968        let mut triple = IoBufs::from(vec![
2969            IoBuf::from(b"a".to_vec()),
2970            IoBuf::from(b"b".to_vec()),
2971            IoBuf::from(b"c".to_vec()),
2972        ]);
2973        assert!(triple.as_single().is_none());
2974        triple.prepend(IoBuf::from(vec![b'0']));
2975        triple.prepend(IoBuf::from(vec![b'1']));
2976        triple.append(IoBuf::from(vec![b'2']));
2977        assert_eq!(triple.copy_to_bytes(triple.remaining()).as_ref(), b"10abc2");
2978
2979        // Appending to an existing triple keeps byte order stable.
2980        let mut triple_append = IoBufs::from(vec![
2981            IoBuf::from(b"x".to_vec()),
2982            IoBuf::from(b"y".to_vec()),
2983            IoBuf::from(b"z".to_vec()),
2984        ]);
2985        triple_append.append(IoBuf::from(vec![b'w']));
2986        assert_eq!(triple_append.coalesce(), b"xyzw");
2987
2988        // coalesce_with_pool on a triple should preserve contents.
2989        let triple_pool = IoBufs::from(vec![
2990            IoBuf::from(b"a".to_vec()),
2991            IoBuf::from(b"b".to_vec()),
2992            IoBuf::from(b"c".to_vec()),
2993        ]);
2994        assert_eq!(triple_pool.coalesce_with_pool(&pool), b"abc");
2995
2996        // coalesce_with_pool on 4+ chunks should read only remaining bytes.
2997        let mut chunked_pool = IoBufs::from(vec![
2998            IoBuf::from(b"a".to_vec()),
2999            IoBuf::from(b"b".to_vec()),
3000            IoBuf::from(b"c".to_vec()),
3001            IoBuf::from(b"d".to_vec()),
3002        ]);
3003        assert_eq!(chunked_pool.remaining(), 4);
3004        chunked_pool.advance(1);
3005        assert_eq!(chunked_pool.coalesce_with_pool(&pool), b"bcd");
3006
3007        // Non-canonical Pair/Triple/Chunked shapes should still expose the first readable chunk.
3008        let pair_second = IoBufs {
3009            inner: IoBufsInner::Pair([IoBuf::default(), IoBuf::from(vec![1u8])]),
3010        };
3011        assert_eq!(pair_second.chunk(), &[1u8]);
3012        let pair_empty = IoBufs {
3013            inner: IoBufsInner::Pair([IoBuf::default(), IoBuf::default()]),
3014        };
3015        assert_eq!(pair_empty.chunk(), b"");
3016
3017        let triple_third = IoBufs {
3018            inner: IoBufsInner::Triple([
3019                IoBuf::default(),
3020                IoBuf::default(),
3021                IoBuf::from(vec![3u8]),
3022            ]),
3023        };
3024        assert_eq!(triple_third.chunk(), &[3u8]);
3025        let triple_second = IoBufs {
3026            inner: IoBufsInner::Triple([
3027                IoBuf::default(),
3028                IoBuf::from(vec![2u8]),
3029                IoBuf::default(),
3030            ]),
3031        };
3032        assert_eq!(triple_second.chunk(), &[2u8]);
3033        let triple_empty = IoBufs {
3034            inner: IoBufsInner::Triple([IoBuf::default(), IoBuf::default(), IoBuf::default()]),
3035        };
3036        assert_eq!(triple_empty.chunk(), b"");
3037
3038        let chunked_second = IoBufs {
3039            inner: IoBufsInner::Chunked(VecDeque::from([IoBuf::default(), IoBuf::from(vec![9u8])])),
3040        };
3041        assert_eq!(chunked_second.chunk(), &[9u8]);
3042        let chunked_empty = IoBufs {
3043            inner: IoBufsInner::Chunked(VecDeque::from([IoBuf::default()])),
3044        };
3045        assert_eq!(chunked_empty.chunk(), b"");
3046    }
3047
3048    #[test]
3049    fn test_iobufsmut_additional_shape_and_conversion_paths() {
3050        // `as_single` accessors should work only for single-shape containers.
3051        let mut single = IoBufsMut::from(IoBufMut::from(b"x"));
3052        assert!(single.as_single().is_some());
3053        assert!(single.as_single_mut().is_some());
3054        single.canonicalize();
3055        assert!(single.is_single());
3056
3057        let mut pair = IoBufsMut::from(vec![IoBufMut::from(b"a"), IoBufMut::from(b"b")]);
3058        assert!(pair.as_single().is_none());
3059        assert!(pair.as_single_mut().is_none());
3060
3061        // Constructor coverage for raw vec and BytesMut sources.
3062        let from_vec = IoBufsMut::from(vec![1u8, 2u8]);
3063        assert_eq!(from_vec.chunk(), &[1u8, 2]);
3064        let from_bytesmut = IoBufsMut::from(BytesMut::from(&b"cd"[..]));
3065        assert_eq!(from_bytesmut.chunk(), b"cd");
3066
3067        // Chunked write path: set_len + copy_from_slice + freeze round-trip.
3068        let mut chunked = IoBufsMut::from(vec![
3069            IoBufMut::with_capacity(1),
3070            IoBufMut::with_capacity(1),
3071            IoBufMut::with_capacity(1),
3072            IoBufMut::with_capacity(1),
3073        ]);
3074        // SAFETY: We only write/read initialized bytes after `copy_from_slice`.
3075        unsafe { chunked.set_len(4) };
3076        chunked.copy_from_slice(b"wxyz");
3077        assert_eq!(chunked.capacity(), 4);
3078        assert_eq!(chunked.remaining(), 4);
3079        let frozen = chunked.freeze();
3080        assert_eq!(frozen.coalesce(), b"wxyz");
3081    }
3082
3083    #[test]
3084    fn test_iobufsmut_coalesce_multi_shape_paths() {
3085        let pool = test_pool();
3086
3087        // Pair: plain coalesce and pool-backed coalesce-with-extra.
3088        let pair = IoBufsMut::from(vec![IoBufMut::from(b"ab"), IoBufMut::from(b"cd")]);
3089        assert_eq!(pair.coalesce(), b"abcd");
3090        let pair = IoBufsMut::from(vec![IoBufMut::from(b"ab"), IoBufMut::from(b"cd")]);
3091        let pair_extra = pair.coalesce_with_pool_extra(&pool, 3);
3092        assert_eq!(pair_extra, b"abcd");
3093        assert!(pair_extra.capacity() >= 7);
3094
3095        // Triple: both coalesce paths should preserve payload and requested spare capacity.
3096        let triple = IoBufsMut::from(vec![
3097            IoBufMut::from(b"a"),
3098            IoBufMut::from(b"b"),
3099            IoBufMut::from(b"c"),
3100        ]);
3101        assert_eq!(triple.coalesce(), b"abc");
3102        let triple = IoBufsMut::from(vec![
3103            IoBufMut::from(b"a"),
3104            IoBufMut::from(b"b"),
3105            IoBufMut::from(b"c"),
3106        ]);
3107        let triple_extra = triple.coalesce_with_pool_extra(&pool, 2);
3108        assert_eq!(triple_extra, b"abc");
3109        assert!(triple_extra.capacity() >= 5);
3110
3111        // Chunked (4+): same expectations as pair/triple for content + capacity.
3112        let chunked = IoBufsMut::from(vec![
3113            IoBufMut::from(b"1"),
3114            IoBufMut::from(b"2"),
3115            IoBufMut::from(b"3"),
3116            IoBufMut::from(b"4"),
3117        ]);
3118        assert_eq!(chunked.coalesce(), b"1234");
3119        let chunked = IoBufsMut::from(vec![
3120            IoBufMut::from(b"1"),
3121            IoBufMut::from(b"2"),
3122            IoBufMut::from(b"3"),
3123            IoBufMut::from(b"4"),
3124        ]);
3125        let chunked_extra = chunked.coalesce_with_pool_extra(&pool, 5);
3126        assert_eq!(chunked_extra, b"1234");
3127        assert!(chunked_extra.capacity() >= 9);
3128    }
3129
3130    #[test]
3131    fn test_iobufsmut_noncanonical_chunk_and_chunk_mut_paths() {
3132        fn no_spare_capacity_buf(pool: &BufferPool) -> IoBufMut {
3133            let mut buf = pool.alloc(1);
3134            let cap = buf.capacity();
3135            // SAFETY: We never read from this buffer in this helper.
3136            unsafe { buf.set_len(cap) };
3137            buf
3138        }
3139        let pool = test_pool();
3140
3141        // `chunk()` should skip empty front buffers across all shapes.
3142        let pair_second = IoBufsMut {
3143            inner: IoBufsMutInner::Pair([IoBufMut::default(), IoBufMut::from(b"b")]),
3144        };
3145        assert_eq!(pair_second.chunk(), b"b");
3146        let pair_empty = IoBufsMut {
3147            inner: IoBufsMutInner::Pair([IoBufMut::default(), IoBufMut::default()]),
3148        };
3149        assert_eq!(pair_empty.chunk(), b"");
3150
3151        let triple_third = IoBufsMut {
3152            inner: IoBufsMutInner::Triple([
3153                IoBufMut::default(),
3154                IoBufMut::default(),
3155                IoBufMut::from(b"c"),
3156            ]),
3157        };
3158        assert_eq!(triple_third.chunk(), b"c");
3159        let triple_second = IoBufsMut {
3160            inner: IoBufsMutInner::Triple([
3161                IoBufMut::default(),
3162                IoBufMut::from(b"b"),
3163                IoBufMut::default(),
3164            ]),
3165        };
3166        assert_eq!(triple_second.chunk(), b"b");
3167        let triple_empty = IoBufsMut {
3168            inner: IoBufsMutInner::Triple([
3169                IoBufMut::default(),
3170                IoBufMut::default(),
3171                IoBufMut::default(),
3172            ]),
3173        };
3174        assert_eq!(triple_empty.chunk(), b"");
3175
3176        let chunked_second = IoBufsMut {
3177            inner: IoBufsMutInner::Chunked(VecDeque::from([
3178                IoBufMut::default(),
3179                IoBufMut::from(b"d"),
3180            ])),
3181        };
3182        assert_eq!(chunked_second.chunk(), b"d");
3183        let chunked_empty = IoBufsMut {
3184            inner: IoBufsMutInner::Chunked(VecDeque::from([IoBufMut::default()])),
3185        };
3186        assert_eq!(chunked_empty.chunk(), b"");
3187
3188        // `chunk_mut()` should skip non-writable fronts and return first writable chunk.
3189        let mut pair_chunk_mut = IoBufsMut {
3190            inner: IoBufsMutInner::Pair([no_spare_capacity_buf(&pool), IoBufMut::with_capacity(2)]),
3191        };
3192        assert!(pair_chunk_mut.chunk_mut().len() >= 2);
3193
3194        let mut pair_chunk_mut_empty = IoBufsMut {
3195            inner: IoBufsMutInner::Pair([
3196                no_spare_capacity_buf(&pool),
3197                no_spare_capacity_buf(&pool),
3198            ]),
3199        };
3200        assert_eq!(pair_chunk_mut_empty.chunk_mut().len(), 0);
3201
3202        let mut triple_chunk_mut = IoBufsMut {
3203            inner: IoBufsMutInner::Triple([
3204                no_spare_capacity_buf(&pool),
3205                no_spare_capacity_buf(&pool),
3206                IoBufMut::with_capacity(3),
3207            ]),
3208        };
3209        assert!(triple_chunk_mut.chunk_mut().len() >= 3);
3210        let mut triple_chunk_mut_second = IoBufsMut {
3211            inner: IoBufsMutInner::Triple([
3212                no_spare_capacity_buf(&pool),
3213                IoBufMut::with_capacity(2),
3214                no_spare_capacity_buf(&pool),
3215            ]),
3216        };
3217        assert!(triple_chunk_mut_second.chunk_mut().len() >= 2);
3218
3219        let mut triple_chunk_mut_empty = IoBufsMut {
3220            inner: IoBufsMutInner::Triple([
3221                no_spare_capacity_buf(&pool),
3222                no_spare_capacity_buf(&pool),
3223                no_spare_capacity_buf(&pool),
3224            ]),
3225        };
3226        assert_eq!(triple_chunk_mut_empty.chunk_mut().len(), 0);
3227
3228        let mut chunked_chunk_mut = IoBufsMut {
3229            inner: IoBufsMutInner::Chunked(VecDeque::from([
3230                IoBufMut::default(),
3231                IoBufMut::with_capacity(4),
3232            ])),
3233        };
3234        assert!(chunked_chunk_mut.chunk_mut().len() >= 4);
3235
3236        let mut chunked_chunk_mut_empty = IoBufsMut {
3237            inner: IoBufsMutInner::Chunked(VecDeque::from([no_spare_capacity_buf(&pool)])),
3238        };
3239        assert_eq!(chunked_chunk_mut_empty.chunk_mut().len(), 0);
3240    }
3241
3242    #[test]
3243    fn test_iobuf_internal_chunk_helpers() {
3244        // `copy_to_bytes_chunked` drops leading empties on zero-length reads
3245        // and asks for canonicalization so the emptied deque collapses back
3246        // to the Single representation.
3247        let mut empty_with_leading = VecDeque::from([IoBuf::default()]);
3248        let (bytes, needs_canonicalize) = copy_to_bytes_chunked(&mut empty_with_leading, 0, "x");
3249        assert!(bytes.is_empty());
3250        assert!(needs_canonicalize);
3251        assert!(empty_with_leading.is_empty());
3252
3253        // Fast path: front chunk can fully satisfy the request.
3254        let mut fast = VecDeque::from([
3255            IoBuf::from(b"ab".to_vec()),
3256            IoBuf::from(b"cd".to_vec()),
3257            IoBuf::from(b"ef".to_vec()),
3258            IoBuf::from(b"gh".to_vec()),
3259        ]);
3260        let (bytes, needs_canonicalize) = copy_to_bytes_chunked(&mut fast, 2, "x");
3261        assert_eq!(bytes.as_ref(), b"ab");
3262        assert!(needs_canonicalize);
3263        assert_eq!(fast.front().expect("front exists").as_ref(), b"cd");
3264
3265        // Slow path: request spans multiple chunks.
3266        let mut slow = VecDeque::from([
3267            IoBuf::from(b"a".to_vec()),
3268            IoBuf::from(b"bc".to_vec()),
3269            IoBuf::from(b"d".to_vec()),
3270            IoBuf::from(b"e".to_vec()),
3271        ]);
3272        let (bytes, needs_canonicalize) = copy_to_bytes_chunked(&mut slow, 3, "x");
3273        assert_eq!(bytes.as_ref(), b"abc");
3274        assert!(needs_canonicalize);
3275
3276        let mut empty_with_leading_mut = VecDeque::from([IoBufMut::default()]);
3277        let (bytes, needs_canonicalize) =
3278            copy_to_bytes_chunked(&mut empty_with_leading_mut, 0, "x");
3279        assert!(bytes.is_empty());
3280        assert!(needs_canonicalize);
3281        assert!(empty_with_leading_mut.is_empty());
3282
3283        // Mirror the fast/slow chunked helper paths for mutable chunks too.
3284        let mut fast_mut = VecDeque::from([
3285            IoBufMut::from(b"ab"),
3286            IoBufMut::from(b"cd"),
3287            IoBufMut::from(b"ef"),
3288            IoBufMut::from(b"gh"),
3289        ]);
3290        let (bytes, needs_canonicalize) = copy_to_bytes_chunked(&mut fast_mut, 2, "x");
3291        assert_eq!(bytes.as_ref(), b"ab");
3292        assert!(needs_canonicalize);
3293        assert_eq!(fast_mut.front().expect("front exists").as_ref(), b"cd");
3294
3295        let mut slow_mut = VecDeque::from([
3296            IoBufMut::from(b"a"),
3297            IoBufMut::from(b"bc"),
3298            IoBufMut::from(b"de"),
3299            IoBufMut::from(b"f"),
3300        ]);
3301        let (bytes, needs_canonicalize) = copy_to_bytes_chunked(&mut slow_mut, 4, "x");
3302        assert_eq!(bytes.as_ref(), b"abcd");
3303        assert!(needs_canonicalize);
3304        assert_eq!(slow_mut.front().expect("front exists").as_ref(), b"e");
3305
3306        // `advance_chunked_front` should skip empties and drain in linear order.
3307        let mut advance_chunked = VecDeque::from([
3308            IoBuf::default(),
3309            IoBuf::from(b"abc".to_vec()),
3310            IoBuf::from(b"d".to_vec()),
3311        ]);
3312        advance_chunked_front(&mut advance_chunked, 2);
3313        assert_eq!(
3314            advance_chunked.front().expect("front exists").as_ref(),
3315            b"c"
3316        );
3317        advance_chunked_front(&mut advance_chunked, 2);
3318        assert!(advance_chunked.is_empty());
3319
3320        // The front-advance helper also has a separate mutable monomorphization.
3321        let mut advance_chunked_mut = VecDeque::from([
3322            IoBufMut::default(),
3323            IoBufMut::from(b"abc"),
3324            IoBufMut::from(b"d"),
3325        ]);
3326        advance_chunked_front(&mut advance_chunked_mut, 2);
3327        assert_eq!(
3328            advance_chunked_mut.front().expect("front exists").as_ref(),
3329            b"c"
3330        );
3331        advance_chunked_front(&mut advance_chunked_mut, 2);
3332        assert!(advance_chunked_mut.is_empty());
3333
3334        // `advance_small_chunks` signals canonicalization when front chunks are exhausted.
3335        let mut small = [IoBuf::default(), IoBuf::from(b"abc".to_vec())];
3336        let needs_canonicalize = advance_small_chunks(&mut small, 2);
3337        assert!(needs_canonicalize);
3338        assert_eq!(small[1].as_ref(), b"c");
3339
3340        let mut small_exact = [
3341            IoBuf::from(b"a".to_vec()),
3342            IoBuf::from(b"b".to_vec()),
3343            IoBuf::from(b"c".to_vec()),
3344        ];
3345        let needs_canonicalize = advance_small_chunks(&mut small_exact, 3);
3346        assert!(needs_canonicalize);
3347        assert_eq!(small_exact[0].remaining(), 0);
3348        assert_eq!(small_exact[1].remaining(), 0);
3349        assert_eq!(small_exact[2].remaining(), 0);
3350
3351        // Small-chunk copy canonicalization is also instantiated for mutable chunks.
3352        let mut small_mut = [
3353            IoBufMut::from(b"a"),
3354            IoBufMut::from(b"bc"),
3355            IoBufMut::from(b"d"),
3356        ];
3357        let (bytes, needs_canonicalize) = copy_to_bytes_small_chunks(&mut small_mut, 3, "x");
3358        assert_eq!(bytes.as_ref(), b"abc");
3359        assert!(needs_canonicalize);
3360        assert_eq!(small_mut[2].as_ref(), b"d");
3361
3362        // `advance_mut_in_chunks` returns whether the request fully fit in writable chunks.
3363        let mut writable = [IoBufMut::with_capacity(2), IoBufMut::with_capacity(1)];
3364        let mut remaining = 3usize;
3365        // SAFETY: We do not read from advanced bytes in this test.
3366        let all_advanced = unsafe { advance_mut_in_chunks(&mut writable, &mut remaining) };
3367        assert!(all_advanced);
3368        assert_eq!(remaining, 0);
3369
3370        // `advance_mut_in_chunks` should skip non-writable chunks.
3371        let pool = test_pool();
3372        let mut full = pool.alloc(1);
3373        // SAFETY: We only mark initialized capacity and never read bytes.
3374        unsafe { full.set_len(full.capacity()) };
3375        let mut writable_after_full = [full, IoBufMut::with_capacity(2)];
3376        let mut remaining = 2usize;
3377        // SAFETY: We do not read from advanced bytes in this test.
3378        let all_advanced =
3379            unsafe { advance_mut_in_chunks(&mut writable_after_full, &mut remaining) };
3380        assert!(all_advanced);
3381        assert_eq!(remaining, 0);
3382
3383        let mut writable_short = [IoBufMut::with_capacity(1), IoBufMut::with_capacity(1)];
3384        let mut remaining = 3usize;
3385        // SAFETY: We do not read from advanced bytes in this test.
3386        let all_advanced = unsafe { advance_mut_in_chunks(&mut writable_short, &mut remaining) };
3387        assert!(!all_advanced);
3388        assert_eq!(remaining, 1);
3389    }
3390
3391    #[test]
3392    fn test_iobufsmut_advance_mut_success_paths() {
3393        // Pair path.
3394        let mut pair = IoBufsMut {
3395            inner: IoBufsMutInner::Pair([IoBufMut::with_capacity(2), IoBufMut::with_capacity(2)]),
3396        };
3397        // SAFETY: We only verify cursor movement (`remaining`) and do not read bytes.
3398        unsafe { pair.advance_mut(3) };
3399        assert_eq!(pair.remaining(), 3);
3400
3401        // Triple path.
3402        let mut triple = IoBufsMut {
3403            inner: IoBufsMutInner::Triple([
3404                IoBufMut::with_capacity(1),
3405                IoBufMut::with_capacity(1),
3406                IoBufMut::with_capacity(1),
3407            ]),
3408        };
3409        // SAFETY: We only verify cursor movement (`remaining`) and do not read bytes.
3410        unsafe { triple.advance_mut(2) };
3411        assert_eq!(triple.remaining(), 2);
3412
3413        // Chunked wrapped-VecDeque path.
3414        let mut wrapped = VecDeque::with_capacity(5);
3415        wrapped.push_back(IoBufMut::with_capacity(1));
3416        wrapped.push_back(IoBufMut::with_capacity(1));
3417        wrapped.push_back(IoBufMut::with_capacity(1));
3418        wrapped.push_back(IoBufMut::with_capacity(1));
3419        wrapped.push_back(IoBufMut::with_capacity(1));
3420        let _ = wrapped.pop_front();
3421        wrapped.push_back(IoBufMut::with_capacity(1));
3422        let (first, second) = wrapped.as_slices();
3423        assert!(!first.is_empty());
3424        assert!(!second.is_empty());
3425
3426        // Force `advance_mut` to consume across the wrapped second slice as well.
3427        let to_advance = first.len() + 1;
3428        let mut chunked = IoBufsMut {
3429            inner: IoBufsMutInner::Chunked(wrapped),
3430        };
3431        let before = chunked.remaining_mut();
3432        // SAFETY: We only verify cursor movement (`remaining`) and do not read bytes.
3433        unsafe { chunked.advance_mut(to_advance) };
3434        assert_eq!(chunked.remaining(), to_advance);
3435        assert_eq!(chunked.remaining_mut(), before - to_advance);
3436    }
3437
3438    #[test]
3439    fn test_iobufsmut_advance_mut_zero_noop_when_full() {
3440        fn full_chunk(pool: &BufferPool) -> IoBufMut {
3441            // Pooled buffers have bounded class capacity (unlike growable Bytes),
3442            // so force len == capacity to make remaining_mut() == 0.
3443            let mut buf = pool.alloc(1);
3444            let cap = buf.capacity();
3445            // SAFETY: We never read from this buffer in this test.
3446            unsafe { buf.set_len(cap) };
3447            buf
3448        }
3449
3450        let pool = test_pool();
3451
3452        // Pair path: fully-written chunks should allow advance_mut(0) as a no-op.
3453        let mut pair = IoBufsMut::from(vec![full_chunk(&pool), full_chunk(&pool)]);
3454        assert!(matches!(pair.inner, IoBufsMutInner::Pair(_)));
3455        assert_eq!(pair.remaining_mut(), 0);
3456        let before = pair.remaining();
3457        // SAFETY: Advancing by 0 does not expose uninitialized bytes.
3458        unsafe { pair.advance_mut(0) };
3459        assert_eq!(pair.remaining(), before);
3460
3461        // Triple path: same no-op behavior.
3462        let mut triple = IoBufsMut::from(vec![
3463            full_chunk(&pool),
3464            full_chunk(&pool),
3465            full_chunk(&pool),
3466        ]);
3467        assert!(matches!(triple.inner, IoBufsMutInner::Triple(_)));
3468        assert_eq!(triple.remaining_mut(), 0);
3469        let before = triple.remaining();
3470        // SAFETY: Advancing by 0 does not expose uninitialized bytes.
3471        unsafe { triple.advance_mut(0) };
3472        assert_eq!(triple.remaining(), before);
3473
3474        // Chunked path: 4+ fully-written chunks should also no-op.
3475        let mut chunked = IoBufsMut::from(vec![
3476            full_chunk(&pool),
3477            full_chunk(&pool),
3478            full_chunk(&pool),
3479            full_chunk(&pool),
3480        ]);
3481        assert!(matches!(chunked.inner, IoBufsMutInner::Chunked(_)));
3482        assert_eq!(chunked.remaining_mut(), 0);
3483        let before = chunked.remaining();
3484        // SAFETY: Advancing by 0 does not expose uninitialized bytes.
3485        unsafe { chunked.advance_mut(0) };
3486        assert_eq!(chunked.remaining(), before);
3487    }
3488
3489    #[test]
3490    #[should_panic(expected = "cannot advance past end of buffer")]
3491    fn test_iobufsmut_advance_mut_past_end_pair() {
3492        let mut pair = IoBufsMut {
3493            inner: IoBufsMutInner::Pair([IoBufMut::with_capacity(1), IoBufMut::with_capacity(1)]),
3494        };
3495        // SAFETY: Intentional panic path coverage.
3496        unsafe { pair.advance_mut(3) };
3497    }
3498
3499    #[test]
3500    #[should_panic(expected = "cannot advance past end of buffer")]
3501    fn test_iobufsmut_advance_mut_past_end_triple() {
3502        let mut triple = IoBufsMut {
3503            inner: IoBufsMutInner::Triple([
3504                IoBufMut::with_capacity(1),
3505                IoBufMut::with_capacity(1),
3506                IoBufMut::with_capacity(1),
3507            ]),
3508        };
3509        // SAFETY: Intentional panic path coverage.
3510        unsafe { triple.advance_mut(4) };
3511    }
3512
3513    #[test]
3514    #[should_panic(expected = "cannot advance past end of buffer")]
3515    fn test_iobufsmut_advance_mut_past_end_chunked() {
3516        let mut chunked = IoBufsMut {
3517            inner: IoBufsMutInner::Chunked(VecDeque::from([
3518                IoBufMut::with_capacity(1),
3519                IoBufMut::with_capacity(1),
3520                IoBufMut::with_capacity(1),
3521                IoBufMut::with_capacity(1),
3522            ])),
3523        };
3524        // SAFETY: Intentional panic path coverage.
3525        unsafe { chunked.advance_mut(5) };
3526    }
3527
3528    #[test]
3529    fn test_iobufsmut_set_len() {
3530        // SAFETY: we don't read the uninitialized bytes.
3531        unsafe {
3532            // Single buffer
3533            let mut bufs = IoBufsMut::from(IoBufMut::with_capacity(16));
3534            bufs.set_len(10);
3535            assert_eq!(bufs.len(), 10);
3536
3537            // Chunked: distributes across chunks [cap 5, cap 10], set 12 -> [5, 7]
3538            let mut bufs = IoBufsMut::from(vec![
3539                IoBufMut::with_capacity(5),
3540                IoBufMut::with_capacity(10),
3541            ]);
3542            bufs.set_len(12);
3543            assert_eq!(bufs.len(), 12);
3544            assert_eq!(bufs.chunk().len(), 5);
3545            bufs.advance(5);
3546            assert_eq!(bufs.chunk().len(), 7);
3547            bufs.advance(7);
3548            assert_eq!(bufs.remaining(), 0);
3549
3550            // Uneven capacities [3, 20, 2], set 18 -> [3, 15, 0].
3551            let mut bufs = IoBufsMut::from(vec![
3552                IoBufMut::with_capacity(3),
3553                IoBufMut::with_capacity(20),
3554                IoBufMut::with_capacity(2),
3555            ]);
3556            bufs.set_len(18);
3557            assert_eq!(bufs.chunk().len(), 3);
3558            bufs.advance(3);
3559            assert_eq!(bufs.chunk().len(), 15);
3560            bufs.advance(15);
3561            assert_eq!(bufs.remaining(), 0);
3562
3563            // Exact total capacity [4, 4], set 8 -> [4, 4]
3564            let mut bufs =
3565                IoBufsMut::from(vec![IoBufMut::with_capacity(4), IoBufMut::with_capacity(4)]);
3566            bufs.set_len(8);
3567            assert_eq!(bufs.chunk().len(), 4);
3568            bufs.advance(4);
3569            assert_eq!(bufs.chunk().len(), 4);
3570            bufs.advance(4);
3571            assert_eq!(bufs.remaining(), 0);
3572
3573            // Zero length preserves caller-provided layout.
3574            let mut bufs =
3575                IoBufsMut::from(vec![IoBufMut::with_capacity(4), IoBufMut::with_capacity(4)]);
3576            bufs.set_len(0);
3577            assert_eq!(bufs.len(), 0);
3578            assert_eq!(bufs.chunk(), b"");
3579        }
3580    }
3581
3582    #[test]
3583    #[should_panic(expected = "set_len(9) exceeds capacity(8)")]
3584    fn test_iobufsmut_set_len_overflow() {
3585        let mut bufs =
3586            IoBufsMut::from(vec![IoBufMut::with_capacity(4), IoBufMut::with_capacity(4)]);
3587        // SAFETY: this will panic before any read.
3588        unsafe { bufs.set_len(9) };
3589    }
3590
3591    #[test]
3592    fn test_encode_with_pool_matches_encode() {
3593        let value = vec![1u8, 2, 3, 4, 5, 6];
3594        assert_encode_with_pool_matches_encode(&value);
3595    }
3596
3597    #[test]
3598    fn test_encode_with_pool_mut_len_matches_encode_size() {
3599        let pool = test_pool();
3600        let value = vec![9u8, 8, 7, 6];
3601
3602        let buf = value.encode_with_pool_mut(&pool);
3603        assert_eq!(buf.len(), value.encode_size());
3604    }
3605
3606    /// Claims a larger encoding than `write` produces, driving the
3607    /// [`EncodeExt`] size asserts in the failing direction.
3608    struct UnderWriter;
3609
3610    impl Write for UnderWriter {
3611        fn write(&self, buf: &mut impl BufMut) {
3612            buf.put_slice(b"ab");
3613        }
3614    }
3615
3616    impl EncodeSize for UnderWriter {
3617        fn encode_size(&self) -> usize {
3618            4
3619        }
3620    }
3621
3622    #[test]
3623    #[should_panic(expected = "write() did not write expected bytes into pooled buffer")]
3624    fn test_encode_with_pool_mut_rejects_short_write() {
3625        let pool = test_pool();
3626        let _ = UnderWriter.encode_with_pool_mut(&pool);
3627    }
3628
3629    #[test]
3630    #[should_panic(expected = "write_bufs() did not write expected bytes")]
3631    fn test_encode_with_pool_rejects_short_write() {
3632        let pool = test_pool();
3633        let _ = UnderWriter.encode_with_pool(&pool);
3634    }
3635
3636    #[test]
3637    fn test_iobuf_encode_with_pool_matches_encode() {
3638        let value = IoBuf::from(vec![0xAB; 512]);
3639        assert_encode_with_pool_matches_encode(&value);
3640    }
3641
3642    #[test]
3643    fn test_nested_container_encode_with_pool_matches_encode() {
3644        let value = (
3645            Some(Bytes::from(vec![0xAA; 256])),
3646            vec![Bytes::from(vec![0xBB; 128]), Bytes::from(vec![0xCC; 64])],
3647        );
3648        assert_encode_with_pool_matches_encode(&value);
3649    }
3650
3651    #[test]
3652    fn test_map_encode_with_pool_matches_encode() {
3653        let mut btree = BTreeMap::new();
3654        btree.insert(2u8, Bytes::from(vec![0xDD; 96]));
3655        btree.insert(1u8, Bytes::from(vec![0xEE; 48]));
3656        assert_encode_with_pool_matches_encode(&btree);
3657
3658        let mut hash = HashMap::new();
3659        hash.insert(2u8, Bytes::from(vec![0x11; 96]));
3660        hash.insert(1u8, Bytes::from(vec![0x22; 48]));
3661        assert_encode_with_pool_matches_encode(&hash);
3662    }
3663
3664    #[test]
3665    fn test_lazy_encode_with_pool_matches_encode() {
3666        let value = Lazy::new(Bytes::from(vec![0x44; 200]));
3667        assert_encode_with_pool_matches_encode(&value);
3668    }
3669
3670    #[test]
3671    fn test_non_empty_range_encode_with_pool_matches_encode() {
3672        let range =
3673            NonEmptyRange::new(Bytes::from(vec![0x10; 32])..Bytes::from(vec![0x20; 48])).unwrap();
3674        assert_encode_with_pool_matches_encode(&range);
3675    }
3676
3677    mod builder_tests {
3678        use super::*;
3679        use commonware_codec::{BufsMut, Encode, Write};
3680
3681        fn builder(capacity: usize) -> Builder {
3682            Builder::new(&test_pool(), NonZeroUsize::new(capacity).unwrap())
3683        }
3684
3685        // Only inline writes, no pushes.
3686        #[test]
3687        fn test_inline_only() {
3688            let mut b = builder(64);
3689            b.put_u32(42);
3690            b.put_u8(7);
3691            let mut r = b.finish();
3692            assert_eq!(r.remaining(), 5);
3693            assert_eq!(r.get_u32(), 42);
3694            assert_eq!(r.get_u8(), 7);
3695        }
3696
3697        // Only zero-copy pushes, no inline writes.
3698        #[test]
3699        fn test_push_only() {
3700            let mut b = builder(64);
3701            let data = Bytes::from(vec![0xAA; 1024]);
3702            b.push(data.clone());
3703            let mut r = b.finish();
3704            assert_eq!(r.remaining(), 1024);
3705            assert_eq!(r.copy_to_bytes(1024), data);
3706        }
3707
3708        // Pushed Bytes appear in the output without a payload copy.
3709        #[test]
3710        fn test_push_is_zero_copy() {
3711            let mut b = builder(64);
3712            b.put_u16(99);
3713            let payload = Bytes::from(vec![0xDD; 1024]);
3714            b.push(payload.clone());
3715            let mut r = b.finish();
3716            r.advance(2);
3717            assert_eq!(r.chunk().as_ptr(), payload.as_ptr());
3718        }
3719
3720        // Interleaved: inline header, zero-copy push, inline trailer.
3721        #[test]
3722        fn test_inline_push_inline() {
3723            let mut b = builder(64);
3724            b.put_u16(99);
3725            let payload = Bytes::from(vec![0xBB; 512]);
3726            b.push(payload.clone());
3727            b.put_u8(1);
3728            let mut r = b.finish();
3729            assert_eq!(r.remaining(), 2 + 512 + 1);
3730            assert_eq!(r.get_u16(), 99);
3731            assert_eq!(r.copy_to_bytes(512), payload);
3732            assert_eq!(r.get_u8(), 1);
3733        }
3734
3735        // Bytes::write_bufs produces identical wire format to Bytes::write.
3736        #[test]
3737        fn test_write_bufs_matches_write() {
3738            let data = Bytes::from(vec![0xCC; 256]);
3739            let mut b = builder(64);
3740            data.write_bufs(&mut b);
3741            let mut bufs = b.finish();
3742
3743            let mut out = vec![0u8; bufs.remaining()];
3744            bufs.copy_to_slice(&mut out);
3745            assert_eq!(out, data.encode().as_ref());
3746        }
3747
3748        // Finishing an unused builder produces empty IoBufs.
3749        #[test]
3750        fn test_empty() {
3751            let bufs = builder(64).finish();
3752            assert_eq!(bufs.remaining(), 0);
3753        }
3754
3755        // Inline writes exceeding capacity panic. `Builder` does not override
3756        // the `BufMut` write methods, so the panic (and message) comes from
3757        // bytes' trait defaults checking `remaining_mut`.
3758        #[test]
3759        #[should_panic(expected = "advance out of bounds")]
3760        fn test_inline_overflow_panics() {
3761            let mut b = builder(1);
3762            let cap = b.remaining_mut();
3763            b.put_slice(&vec![0xFF; cap]);
3764            b.put_u8(1); // exceeds capacity
3765        }
3766
3767        // Pushing empty Bytes is a no-op.
3768        #[test]
3769        fn test_empty_push_ignored() {
3770            let mut b = builder(64);
3771            b.push(Bytes::new());
3772            b.put_u8(1);
3773            let bufs = b.finish();
3774            assert_eq!(bufs.remaining(), 1);
3775        }
3776
3777        // Consecutive pushes without inline writes between them.
3778        #[test]
3779        fn test_multiple_pushes() {
3780            let mut b = builder(64);
3781            let a = Bytes::from(vec![0xAA; 100]);
3782            let c = Bytes::from(vec![0xCC; 200]);
3783            b.push(a.clone());
3784            b.push(c.clone());
3785            let mut r = b.finish();
3786            assert_eq!(r.remaining(), 300);
3787            assert_eq!(r.copy_to_bytes(100), a);
3788            assert_eq!(r.copy_to_bytes(200), c);
3789        }
3790
3791        // put() exceeding capacity panics (in bytes' trait default).
3792        #[test]
3793        #[should_panic(expected = "advance out of bounds")]
3794        fn test_put_exceeding_capacity_panics() {
3795            let mut b = builder(1);
3796            let cap = b.remaining_mut();
3797            let src = Bytes::from(vec![0xAB; cap + 1]);
3798            b.put(src);
3799        }
3800
3801        // put_slice() exceeding capacity panics (in bytes' trait default).
3802        #[test]
3803        #[should_panic(expected = "advance out of bounds")]
3804        fn test_put_slice_exceeding_capacity_panics() {
3805            let mut b = builder(1);
3806            let cap = b.remaining_mut();
3807            b.put_slice(&vec![0xFE; cap + 1]);
3808        }
3809
3810        // Simulates a multi-field struct: [u16 | Bytes (via push) | u32].
3811        // Verifies write_bufs produces identical wire format to write.
3812        #[test]
3813        fn test_multi_field_struct_equivalence() {
3814            let header: u16 = 0xCAFE;
3815            let payload = Bytes::from(vec![0xDD; 1024]);
3816            let trailer: u32 = 0xDEADBEEF;
3817
3818            // Flat encoding via write.
3819            let size = header.encode_size() + payload.encode_size() + trailer.encode_size();
3820            let mut flat = BytesMut::with_capacity(size);
3821            header.write(&mut flat);
3822            payload.write(&mut flat);
3823            trailer.write(&mut flat);
3824
3825            // Multi-buffer encoding via write_bufs.
3826            let mut b = builder(64);
3827            header.write(&mut b);
3828            payload.write_bufs(&mut b);
3829            trailer.write(&mut b);
3830            let mut bufs = b.finish();
3831
3832            let mut out = vec![0u8; bufs.remaining()];
3833            bufs.copy_to_slice(&mut out);
3834            assert_eq!(out, flat.as_ref());
3835        }
3836
3837        // encode_with_pool (Builder path) matches encode (flat BytesMut path).
3838        #[test]
3839        fn test_encode_with_pool_matches_encode() {
3840            let pool = test_pool();
3841            let data = Bytes::from(vec![0xEE; 500]);
3842            let mut pooled = data.encode_with_pool(&pool);
3843            let baseline = data.encode();
3844            let mut out = vec![0u8; pooled.remaining()];
3845            pooled.copy_to_slice(&mut out);
3846            assert_eq!(out, baseline.as_ref());
3847        }
3848
3849        // Exercise remaining_mut, chunk_mut, and advance_mut directly.
3850        #[test]
3851        fn test_chunk_mut_and_advance_mut() {
3852            let mut b = builder(64);
3853            let initial = b.remaining_mut();
3854            assert!(initial >= 64);
3855            let chunk = b.chunk_mut();
3856            chunk[0..1].copy_from_slice(&[0xAB]);
3857            // SAFETY: We just wrote 1 byte into chunk_mut above.
3858            unsafe { b.advance_mut(1) };
3859            assert_eq!(b.remaining_mut(), initial - 1);
3860            let mut r = b.finish();
3861            assert_eq!(r.remaining(), 1);
3862            assert_eq!(r.get_u8(), 0xAB);
3863        }
3864
3865        // Writing past a full buffer panics (fixed capacity, with the panic coming
3866        // from bytes' trait default).
3867        #[test]
3868        #[should_panic(expected = "advance out of bounds")]
3869        fn test_write_past_full_panics() {
3870            let mut b = builder(1);
3871            let cap = b.remaining_mut();
3872            b.put_slice(&vec![0xFF; cap]); // fill the buffer completely
3873            assert_eq!(b.remaining_mut(), 0);
3874            b.put_u8(0x42); // panics
3875        }
3876
3877        // Push at offset 0 with inline trailer exercises finish branch
3878        // where offset == pos (no inline prefix before push).
3879        #[test]
3880        fn test_push_at_start_with_trailer() {
3881            let mut b = builder(64);
3882            let payload = Bytes::from(vec![0xCC; 32]);
3883            b.push(payload.clone());
3884            b.put_u8(0x01);
3885            let mut r = b.finish();
3886            assert_eq!(r.remaining(), 33);
3887            assert_eq!(r.copy_to_bytes(32), payload);
3888            assert_eq!(r.get_u8(), 0x01);
3889        }
3890    }
3891}