Skip to main content

qubit_io/buffered/
buffered_output.rs

1// =============================================================================
2//    Copyright (c) 2026 Haixing Hu.
3//
4//    SPDX-License-Identifier: Apache-2.0
5//
6//    Licensed under the Apache License, Version 2.0.
7// =============================================================================
8
9use std::io::{
10    Error,
11    ErrorKind,
12    Result,
13    Seek,
14    SeekFrom,
15    Write,
16};
17
18use crate::buffered::DEFAULT_BUFFER_CAPACITY;
19use crate::{
20    Buffer,
21    Output,
22};
23
24/// Buffered unit output over a wrapped output sink.
25///
26/// This type keeps a fixed-size unit buffer in front of an underlying output so
27/// small unit writes can be accumulated before they are written to the I/O
28/// target. Large writes may bypass the buffer after pending buffered units
29/// have been flushed.
30///
31/// `BufferedOutput` is deliberately unit-oriented. It performs no binary
32/// encoding, text encoding, or record framing. Higher-level writers can either
33/// use the standard [`Write`] implementation or write directly into
34/// [`Self::spare_buffer_mut`] or [`Self::spare_raw_parts_mut`] and then call
35/// [`Self::advance`] or [`Self::advance_unchecked`] after validating the range
36/// they initialized. Callers that need to recover the wrapped writer should
37/// call [`Write::flush`] first, then use [`Self::into_parts`].
38#[derive(Debug)]
39pub struct BufferedOutput<O>
40where
41    O: Output,
42    O::Item: Copy + Default,
43{
44    inner: O,
45    buffer: Buffer<O::Item>,
46}
47
48impl<O> BufferedOutput<O>
49where
50    O: Output,
51    O::Item: Copy + Default,
52{
53    /// Creates a buffered unit output with the default capacity.
54    ///
55    /// # Parameters
56    ///
57    /// * `inner` - The output that receives units when the internal buffer is
58    ///   flushed.
59    ///
60    /// # Returns
61    ///
62    /// A new buffered unit output using `DEFAULT_BUFFER_CAPACITY`.
63    #[inline(always)]
64    #[must_use]
65    pub fn new(inner: O) -> Self {
66        Self::with_capacity(inner, DEFAULT_BUFFER_CAPACITY)
67    }
68
69    /// Creates a buffered unit output with at least the requested capacity.
70    ///
71    /// # Parameters
72    ///
73    /// * `inner` - The output that receives units when the internal buffer is
74    ///   flushed.
75    /// * `capacity` - The requested internal buffer capacity in units.
76    ///
77    /// # Returns
78    ///
79    /// A new buffered unit output whose actual buffer capacity is
80    /// `capacity.max(1)`.
81    #[inline(always)]
82    #[must_use]
83    pub fn with_capacity(inner: O, capacity: usize) -> Self {
84        Self {
85            inner,
86            buffer: Buffer::with_capacity(capacity),
87        }
88    }
89
90    /// Returns a shared reference to the wrapped writer.
91    ///
92    /// # Returns
93    ///
94    /// An immutable reference to the underlying writer.  Pending bytes may
95    /// still be present in the internal buffer and are not flushed by this
96    /// method.
97    #[inline(always)]
98    pub const fn inner(&self) -> &O {
99        &self.inner
100    }
101
102    /// Returns an exclusive reference to the wrapped writer.
103    ///
104    /// Pending bytes may still be present in the internal buffer and are not
105    /// flushed by this method.
106    ///
107    /// # Returns
108    ///
109    /// A mutable reference to the underlying writer.
110    #[inline(always)]
111    pub fn inner_mut(&mut self) -> &mut O {
112        &mut self.inner
113    }
114
115    /// Returns the internal buffer capacity.
116    ///
117    /// # Returns
118    ///
119    /// The total number of units that can be held by the internal buffer.
120    #[inline(always)]
121    #[must_use]
122    pub fn capacity(&self) -> usize {
123        self.buffer.capacity()
124    }
125
126    /// Returns the unused capacity in the internal buffer.
127    ///
128    /// # Returns
129    ///
130    /// The number of bytes that can still be appended to the internal buffer
131    /// before it must be flushed.
132    #[inline(always)]
133    #[must_use]
134    pub fn spare_capacity(&self) -> usize {
135        self.buffer.spare_capacity()
136    }
137
138    /// Returns the unused portion of the internal buffer.
139    ///
140    /// Callers may write initialized bytes into the returned slice and then
141    /// call [`Self::advance`] with the number of bytes written.
142    ///
143    /// # Returns
144    ///
145    /// A mutable slice over the spare buffer capacity.
146    #[inline(always)]
147    #[must_use]
148    pub fn spare_buffer_mut(&mut self) -> &mut [O::Item] {
149        let limit = self.buffer.limit();
150        &mut self.buffer.data_mut()[limit..]
151    }
152
153    /// Returns raw spare-buffer parts for hot-path callers.
154    ///
155    /// The returned slice is the full internal backing storage. `index` is the
156    /// start of the spare byte window, and `count` is the number of spare
157    /// bytes. Callers that need a slice can use `&mut buffer[index..index +
158    /// count]`; callers that already validated bounds can pass `buffer` and
159    /// `index` directly to indexed unchecked codecs.
160    ///
161    /// Mutating bytes outside `index..index + count` changes pending output
162    /// bytes and may corrupt the logical stream.
163    ///
164    /// # Returns
165    ///
166    /// The backing storage, the spare start index, and the spare byte count.
167    #[inline(always)]
168    #[must_use]
169    pub fn spare_raw_parts_mut(&mut self) -> (&mut [O::Item], usize, usize) {
170        let index = self.buffer.limit();
171        let count = self.buffer.spare_capacity();
172        (self.buffer.data_mut(), index, count)
173    }
174
175    /// Marks `count` bytes from [`Self::spare_buffer_mut`] as written.
176    ///
177    /// # Parameters
178    ///
179    /// * `count` - Number of bytes initialized by the caller.
180    ///
181    /// # Panics
182    ///
183    /// Panics when `count` exceeds [`Self::spare_capacity`].
184    #[inline(always)]
185    pub fn advance(&mut self, count: usize) {
186        assert!(
187            count <= self.spare_capacity(),
188            "cannot advance beyond spare output buffer"
189        );
190        // SAFETY: The assertion proves that `count` is within spare capacity.
191        unsafe {
192            self.buffer.advance_unchecked(count);
193        }
194    }
195
196    /// Marks spare bytes as written without checking bounds.
197    ///
198    /// # Parameters
199    ///
200    /// * `count` - Number of initialized spare bytes to make pending for
201    ///   output.
202    ///
203    /// # Safety
204    ///
205    /// The caller must guarantee that `count <= self.spare_capacity()` and
206    /// that the corresponding bytes returned by [`Self::spare_buffer_mut`]
207    /// have been initialized.
208    #[inline(always)]
209    pub unsafe fn advance_unchecked(&mut self, count: usize) {
210        // SAFETY: The caller guarantees that `count` is within spare capacity.
211        unsafe {
212            self.buffer.advance_unchecked(count);
213        }
214    }
215
216    /// Writes bytes into the internal buffer without checking spare capacity.
217    ///
218    /// # Parameters
219    ///
220    /// * `input` - The source bytes.
221    /// * `input_index` - The starting index in `input`.
222    /// * `count` - The number of bytes to copy.
223    ///
224    /// # Safety
225    ///
226    /// The caller must ensure that `input_index..input_index + count` is valid
227    /// in `input`, that `count <= self.spare_capacity()`, and that the copied
228    /// source range does not overlap with the destination range in the internal
229    /// buffer.
230    #[inline(always)]
231    unsafe fn write_to_buffer_unchecked(
232        &mut self,
233        input: &[O::Item],
234        input_index: usize,
235        count: usize,
236    ) {
237        // SAFETY: The caller upholds `Buffer::copy_from_unchecked` range and
238        // non-overlap requirements.
239        unsafe {
240            self.buffer.copy_from_unchecked(input, input_index, count);
241        }
242    }
243}
244
245impl<O> BufferedOutput<O>
246where
247    O: Output,
248    O::Item: Copy + Default,
249{
250    /// Consumes this buffered output without flushing pending bytes.
251    ///
252    /// This method performs no I/O. Pending bytes that have been accepted into
253    /// the internal buffer but not written to the wrapped writer are returned
254    /// as the second tuple item.
255    ///
256    /// # Returns
257    ///
258    /// The wrapped writer and pending bytes in logical write order.
259    #[inline(always)]
260    #[must_use]
261    pub fn into_parts(self) -> (O, Vec<O::Item>) {
262        let pending = self.pending_slice().to_vec();
263        (self.inner, pending)
264    }
265
266    /// Ensures that at least `count` bytes are available in the spare buffer.
267    ///
268    /// # Parameters
269    ///
270    /// * `count` - Number of spare bytes required.
271    ///
272    /// # Errors
273    ///
274    /// Returns any non-interrupted I/O error produced while flushing buffered
275    /// bytes. Returns [`ErrorKind::InvalidInput`] if `count` exceeds the buffer
276    /// capacity. Returns [`ErrorKind::InvalidData`] if the wrapped writer
277    /// reports more bytes than the pending buffer range contained.
278    pub fn ensure_spare_capacity(&mut self, count: usize) -> Result<()> {
279        if count > self.buffer.capacity() {
280            return Err(Error::new(
281                ErrorKind::InvalidInput,
282                "requested spare capacity exceeds buffered output capacity",
283            ));
284        }
285        if self.spare_capacity() < count {
286            self.flush_buffer()?;
287        }
288        Ok(())
289    }
290
291    /// Writes all bytes through the internal buffer.
292    ///
293    /// Small inputs are appended to the internal buffer.  Inputs that do not
294    /// fit may flush the buffer first, and inputs at least as large as the
295    /// buffer may be written directly to the wrapped writer.
296    ///
297    /// # Parameters
298    ///
299    /// * `input` - The bytes to write.
300    ///
301    /// # Returns
302    ///
303    /// `Ok(())` after all bytes from `input` have been accepted.
304    ///
305    /// # Errors
306    ///
307    /// Returns any I/O error produced while flushing pending bytes or writing a
308    /// large input directly to the wrapped writer. Flush failures include
309    /// [`ErrorKind::WriteZero`] if the writer reports that zero bytes were
310    /// written before the buffer is drained, and [`ErrorKind::InvalidData`] if
311    /// it reports more bytes than the requested range contained.
312    ///
313    /// # Safety
314    ///
315    /// The caller must guarantee that `input_index..input_index + count` is a
316    /// valid range inside `input` and that the addition does not overflow.
317    #[inline]
318    pub unsafe fn write_all_unchecked(
319        &mut self,
320        input: &[O::Item],
321        input_index: usize,
322        count: usize,
323    ) -> Result<()> {
324        debug_assert!(
325            input_index
326                .checked_add(count)
327                .is_some_and(|end| end <= input.len()),
328            "unchecked write range exceeds input buffer"
329        );
330        if count < self.spare_capacity() {
331            // SAFETY: The branch proves that the input fits in spare capacity.
332            unsafe {
333                self.write_to_buffer_unchecked(input, input_index, count);
334            }
335            Ok(())
336        } else {
337            // SAFETY: The caller guarantees the source range is valid.
338            unsafe { self.write_all_cold(input, input_index, count) }
339        }
340    }
341
342    /// Handles slow-path raw writes that must flush or bypass the buffer.
343    ///
344    /// # Parameters
345    ///
346    /// * `input` - The bytes to write after the fast path determined that they
347    ///   do not fit comfortably in the current spare buffer capacity.
348    ///
349    /// # Returns
350    ///
351    /// `Ok(())` after all bytes from `input` have been accepted either by the
352    /// buffer or by the wrapped writer.
353    ///
354    /// # Errors
355    ///
356    /// Returns any I/O error produced while flushing pending bytes or writing a
357    /// large input directly to the wrapped writer. Flush failures include
358    /// [`ErrorKind::WriteZero`] if the writer reports that zero bytes were
359    /// written before the buffer is drained, and [`ErrorKind::InvalidData`] if
360    /// it reports more bytes than the requested range contained.
361    #[cold]
362    #[inline(never)]
363    unsafe fn write_all_cold(
364        &mut self,
365        input: &[O::Item],
366        input_index: usize,
367        count: usize,
368    ) -> Result<()> {
369        if count > self.spare_capacity() {
370            self.flush_buffer()?;
371        }
372        if count >= self.buffer.capacity() {
373            // SAFETY: The range covers the full source slice.
374            unsafe { self.write_all_inner_unchecked(input, input_index, count) }
375        } else {
376            // SAFETY: After the optional flush, any input smaller than the
377            // buffer capacity fits in the empty or sufficiently spare buffer.
378            unsafe {
379                self.write_to_buffer_unchecked(input, input_index, count);
380            }
381            Ok(())
382        }
383    }
384
385    /// Handles slow-path raw writes for [`Write::write`] semantics.
386    ///
387    /// The method preserves `Write::write` behavior: it may accept fewer bytes
388    /// than the input length when the write is delegated directly to the
389    /// wrapped writer.
390    ///
391    /// # Parameters
392    ///
393    /// * `input` - The bytes to write after the fast path determined that they
394    ///   do not fit comfortably in the current spare buffer capacity.
395    ///
396    /// # Returns
397    ///
398    /// The number of bytes accepted.  Buffered writes return `input.len()`;
399    /// direct writes return the byte count reported by the wrapped writer.
400    ///
401    /// # Errors
402    ///
403    /// Returns any I/O error produced while flushing pending bytes or writing a
404    /// large input directly to the wrapped writer. Flush failures include
405    /// [`ErrorKind::WriteZero`] if the writer reports that zero bytes were
406    /// written before the buffer is drained, and [`ErrorKind::InvalidData`] if
407    /// it reports more bytes than the requested range contained.
408    #[cold]
409    #[inline(never)]
410    unsafe fn write_cold(
411        &mut self,
412        input: &[O::Item],
413        input_index: usize,
414        count: usize,
415    ) -> Result<usize> {
416        if count > self.spare_capacity() {
417            self.flush_buffer()?;
418        }
419        if count >= self.buffer.capacity() {
420            // SAFETY: The range covers the full source slice.
421            unsafe { self.write_inner_unchecked(input, input_index, count) }
422        } else {
423            // SAFETY: After the optional flush, any input smaller than the
424            // buffer capacity fits in the empty or sufficiently spare buffer.
425            unsafe {
426                self.write_to_buffer_unchecked(input, input_index, count);
427            }
428            Ok(count)
429        }
430    }
431
432    /// Flushes buffered bytes to the wrapped writer.
433    ///
434    /// The method retries interrupted writes.  If an error occurs after some
435    /// bytes have been written, the already-written bytes are removed from the
436    /// front of the buffer and the unwritten suffix is kept for a later retry.
437    ///
438    /// # Returns
439    ///
440    /// `Ok(())` once all currently buffered bytes have been written to the
441    /// wrapped writer.
442    ///
443    /// # Errors
444    ///
445    /// Returns any non-interrupted I/O error produced by the wrapped writer.
446    /// Returns [`ErrorKind::WriteZero`] if the writer reports a zero-length
447    /// write before all buffered bytes are drained. Returns
448    /// [`ErrorKind::InvalidData`] if the writer reports more bytes than the
449    /// pending buffer range contained.
450    pub fn flush_buffer(&mut self) -> Result<()> {
451        while !self.buffer.is_empty() {
452            let position = self.buffer.position();
453            let available = self.buffer.available();
454            // SAFETY: `position..position + available` is the current readable
455            // range maintained by `Buffer`.
456            match unsafe {
457                self.inner.write_unchecked(
458                    self.buffer.data(),
459                    position,
460                    available,
461                )
462            } {
463                Ok(0) => {
464                    self.buffer.compact();
465                    return Err(Error::new(
466                        ErrorKind::WriteZero,
467                        "failed to write buffered data",
468                    ));
469                }
470                Ok(written) => {
471                    if let Err(error) = validate_write_count(written, available)
472                    {
473                        self.buffer.compact();
474                        return Err(error);
475                    }
476                    // SAFETY: The validated count is in `0..=available`.
477                    unsafe {
478                        self.buffer.consume_unchecked(written);
479                    }
480                }
481                Err(error) if error.kind() == ErrorKind::Interrupted => {}
482                Err(error) => {
483                    self.buffer.compact();
484                    return Err(error);
485                }
486            }
487        }
488        self.buffer.clear();
489        Ok(())
490    }
491
492    /// Flushes buffered bytes and then flushes the wrapped writer.
493    ///
494    /// # Returns
495    ///
496    /// `Ok(())` once pending buffered bytes have been written and the wrapped
497    /// writer's own flush operation succeeds.
498    ///
499    /// # Errors
500    ///
501    /// Returns any non-interrupted I/O error produced while flushing buffered
502    /// bytes, [`ErrorKind::WriteZero`] if the wrapped writer cannot make
503    /// progress while draining the buffer, [`ErrorKind::InvalidData`] if the
504    /// writer reports an impossible byte count, or any error returned by
505    /// [`Write::flush`] on the wrapped writer.
506    #[inline(always)]
507    fn flush_all(&mut self) -> Result<()> {
508        self.flush_buffer()
509            .and_then(|()| Output::flush(&mut self.inner))
510    }
511
512    /// Flushes buffered units and then flushes the wrapped output.
513    ///
514    /// # Returns
515    ///
516    /// `Ok(())` once pending buffered units and the wrapped output are
517    /// flushed.
518    ///
519    /// # Errors
520    ///
521    /// Returns any error produced while draining buffered units or flushing
522    /// the wrapped output.
523    #[inline(always)]
524    pub fn flush(&mut self) -> Result<()> {
525        self.flush_all()
526    }
527
528    /// Writes bytes from the input slice and reports the accepted byte count.
529    ///
530    /// This is the buffered implementation for [`Write::write`]-style callers.
531    /// Small inputs are appended to the buffer and reported as fully accepted;
532    /// large inputs may be delegated to the wrapped writer after pending bytes
533    /// are flushed.
534    ///
535    /// # Parameters
536    ///
537    /// * `input` - The bytes to write.
538    ///
539    /// # Returns
540    ///
541    /// The number of bytes accepted.  Buffered writes return `input.len()`;
542    /// direct writes return the byte count reported by the wrapped writer.
543    ///
544    /// # Errors
545    ///
546    /// Returns any I/O error produced while flushing pending bytes or writing a
547    /// large input directly to the wrapped writer. Flush failures include
548    /// [`ErrorKind::WriteZero`] if the writer reports that zero bytes were
549    /// written before the buffer is drained, and [`ErrorKind::InvalidData`] if
550    /// it reports more bytes than the requested range contained.
551    ///
552    /// # Safety
553    ///
554    /// The caller must guarantee that `input_index..input_index + count` is a
555    /// valid range inside `input` and that the addition does not overflow.
556    #[inline]
557    pub unsafe fn write_from_unchecked(
558        &mut self,
559        input: &[O::Item],
560        input_index: usize,
561        count: usize,
562    ) -> Result<usize> {
563        debug_assert!(
564            input_index
565                .checked_add(count)
566                .is_some_and(|end| end <= input.len()),
567            "unchecked write range exceeds input buffer"
568        );
569        if count < self.spare_capacity() {
570            // SAFETY: The branch proves that the input fits in spare capacity.
571            unsafe {
572                self.write_to_buffer_unchecked(input, input_index, count);
573            }
574            Ok(count)
575        } else {
576            // SAFETY: The caller guarantees the source range is valid.
577            unsafe { self.write_cold(input, input_index, count) }
578        }
579    }
580
581    /// Flushes pending bytes before seeking the wrapped writer.
582    ///
583    /// # Parameters
584    ///
585    /// * `position` - The target seek position passed to the wrapped writer.
586    ///
587    /// # Returns
588    ///
589    /// The new stream position reported by the wrapped writer.
590    ///
591    /// # Errors
592    ///
593    /// Returns any non-interrupted I/O error produced while flushing buffered
594    /// bytes, [`ErrorKind::WriteZero`] if the wrapped writer cannot make
595    /// progress while draining the buffer, [`ErrorKind::InvalidData`] if the
596    /// writer reports an impossible byte count, or any error returned by
597    /// [`Seek::seek`] on the wrapped writer.
598    #[inline(always)]
599    fn flush_then_seek(&mut self, position: SeekFrom) -> Result<u64>
600    where
601        O: Seek,
602    {
603        self.flush_buffer().and_then(|()| self.inner.seek(position))
604    }
605
606    /// Returns pending bytes currently stored in the internal buffer.
607    ///
608    /// # Returns
609    ///
610    /// A slice over bytes accepted by this output but not yet written to the
611    /// wrapped writer.
612    #[inline(always)]
613    fn pending_slice(&self) -> &[O::Item] {
614        &self.buffer.data()[self.buffer.position()..self.buffer.limit()]
615    }
616
617    /// Writes bytes to the wrapped writer and validates the reported count.
618    ///
619    /// # Parameters
620    ///
621    /// * `input` - Source storage.
622    /// * `input_index` - Start index inside `input`.
623    /// * `count` - Maximum number of bytes to write.
624    ///
625    /// # Returns
626    ///
627    /// The number of bytes accepted by the wrapped writer.
628    ///
629    /// # Errors
630    ///
631    /// Returns the wrapped writer's I/O error, or [`ErrorKind::InvalidData`]
632    /// if it reports a byte count larger than `count`.
633    ///
634    /// # Safety
635    ///
636    /// The caller must guarantee that `input_index..input_index + count` is a
637    /// valid range inside `input` and that the addition does not overflow.
638    #[inline(always)]
639    unsafe fn write_inner_unchecked(
640        &mut self,
641        input: &[O::Item],
642        input_index: usize,
643        count: usize,
644    ) -> Result<usize> {
645        // SAFETY: The caller guarantees the source range is valid.
646        let written =
647            unsafe { self.inner.write_unchecked(input, input_index, count) }?;
648        validate_write_count(written, count)?;
649        Ok(written)
650    }
651
652    /// Writes all bytes in an indexed source range to the wrapped writer.
653    ///
654    /// # Parameters
655    ///
656    /// * `input` - Source storage.
657    /// * `input_index` - Start index inside `input`.
658    /// * `count` - Number of bytes to write.
659    ///
660    /// # Errors
661    ///
662    /// Returns the wrapped writer's I/O error, [`ErrorKind::WriteZero`] if the
663    /// writer cannot make progress, or [`ErrorKind::InvalidData`] if it
664    /// reports an impossible byte count.
665    ///
666    /// # Safety
667    ///
668    /// The caller must guarantee that `input_index..input_index + count` is a
669    /// valid range inside `input` and that the addition does not overflow.
670    unsafe fn write_all_inner_unchecked(
671        &mut self,
672        input: &[O::Item],
673        input_index: usize,
674        count: usize,
675    ) -> Result<()> {
676        let mut written = 0;
677        while written < count {
678            let remaining = count - written;
679            // SAFETY: `written < count`, so this suffix remains inside the
680            // caller-validated source range.
681            match unsafe {
682                self.write_inner_unchecked(
683                    input,
684                    input_index + written,
685                    remaining,
686                )
687            } {
688                Ok(0) => {
689                    return Err(Error::new(
690                        ErrorKind::WriteZero,
691                        "failed to write whole buffer",
692                    ));
693                }
694                Ok(count) => written += count,
695                Err(error) if error.kind() == ErrorKind::Interrupted => {}
696                Err(error) => return Err(error),
697            }
698        }
699        Ok(())
700    }
701}
702
703impl<O> Write for BufferedOutput<O>
704where
705    O: Output<Item = u8>,
706{
707    /// Writes bytes through the internal buffer.
708    #[inline(always)]
709    fn write(&mut self, buffer: &[u8]) -> Result<usize> {
710        // SAFETY: The full input slice is a valid source range.
711        unsafe { self.write_from_unchecked(buffer, 0, buffer.len()) }
712    }
713
714    /// Writes all bytes through the internal buffer.
715    #[inline(always)]
716    fn write_all(&mut self, buffer: &[u8]) -> Result<()> {
717        // SAFETY: The full input slice is a valid source range.
718        unsafe { self.write_all_unchecked(buffer, 0, buffer.len()) }
719    }
720
721    /// Flushes the internal buffer and then the wrapped writer.
722    #[inline(always)]
723    fn flush(&mut self) -> Result<()> {
724        self.flush_all()
725    }
726}
727
728impl<O> Seek for BufferedOutput<O>
729where
730    O: Output<Item = u8> + Seek,
731{
732    /// Flushes pending bytes before seeking the wrapped writer.
733    #[inline(always)]
734    fn seek(&mut self, position: SeekFrom) -> Result<u64> {
735        self.flush_then_seek(position)
736    }
737}
738
739/// Validates a byte count returned by a wrapped writer.
740///
741/// # Parameters
742///
743/// * `written` - Byte count reported by the wrapped writer.
744/// * `requested` - Maximum byte count requested from the wrapped writer.
745///
746/// # Errors
747///
748/// Returns [`ErrorKind::InvalidData`] when the wrapped writer reports more
749/// bytes than the source range contained.
750#[inline(always)]
751fn validate_write_count(written: usize, requested: usize) -> Result<()> {
752    if written > requested {
753        return Err(Error::new(
754            ErrorKind::InvalidData,
755            format!(
756                "writer reported {written} bytes for a {requested}-byte buffer"
757            ),
758        ));
759    }
760    Ok(())
761}