Skip to main content

qubit_io/ext/
read_ext.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// =============================================================================
8use std::io::{
9    Error,
10    ErrorKind,
11    Read,
12    Result,
13    Write,
14    copy as copy_all,
15};
16use std::string::FromUtf8Error;
17
18use crate::Streams;
19use crate::util::{
20    try_reserve_string,
21    try_reserve_vec,
22};
23
24/// Default stack buffer size used by discard operations.
25const DISCARD_BUFFER_SIZE: usize = 8 * 1024;
26
27/// Default stack buffer size used by bounded read operations.
28const READ_TO_END_BUFFER_SIZE: usize = 8 * 1024;
29
30/// Extension methods for [`Read`] values.
31///
32/// `ReadExt` fills small semantic gaps in the standard [`Read`] trait while
33/// keeping the same blocking and error model. The methods are implemented for
34/// every type that implements [`Read`], including `dyn Read` trait objects.
35///
36/// # Examples
37/// ```
38/// use qubit_io::ReadExt;
39/// use std::io::Cursor;
40///
41/// let mut input = Cursor::new(b"abcdef".to_vec());
42/// let header = input.read_exact_array::<2>()?;
43/// let payload = input.read_exact_vec_limited(4, 16)?;
44///
45/// assert_eq!(*b"ab", header);
46/// assert_eq!(b"cdef", payload.as_slice());
47/// # Ok::<(), std::io::Error>(())
48/// ```
49pub trait ReadExt: Read {
50    /// Reads bytes into a range of `buffer` without checking the range bounds
51    /// in release builds.
52    ///
53    /// This method delegates to [`Read::read`] after creating the target slice
54    /// with raw pointer arithmetic. It performs at most one read operation and
55    /// returns the number of bytes read, keeping the same short-read and error
56    /// behavior as [`Read::read`].
57    ///
58    /// # Parameters
59    /// - `buffer`: Destination buffer.
60    /// - `start_index`: Start offset inside `buffer`.
61    /// - `count`: Maximum number of bytes to read.
62    ///
63    /// # Returns
64    /// The number of bytes written into `buffer[start_index..start_index +
65    /// count]`. The value is in `0..=count`.
66    ///
67    /// # Errors
68    /// Returns the error reported by [`Read::read`].
69    ///
70    /// # Safety
71    /// The caller must guarantee that `start_index..start_index + count` is a
72    /// valid range within `buffer` and that `start_index + count` does not
73    /// overflow `usize`.
74    unsafe fn read_unchecked(
75        &mut self,
76        buffer: &mut [u8],
77        start_index: usize,
78        count: usize,
79    ) -> Result<usize>;
80
81    /// Reads exactly `count` bytes into a range of `buffer` without checking
82    /// the range bounds in release builds.
83    ///
84    /// This method delegates to [`Read::read_exact`] after creating the target
85    /// slice with raw pointer arithmetic. It keeps the same blocking and error
86    /// behavior as [`Read::read_exact`].
87    ///
88    /// # Parameters
89    /// - `buffer`: Destination buffer.
90    /// - `start_index`: Start offset inside `buffer`.
91    /// - `count`: Number of bytes to read.
92    ///
93    /// # Errors
94    /// Returns the error reported by [`Read::read_exact`], including
95    /// [`ErrorKind::UnexpectedEof`] when EOF is reached before `count` bytes
96    /// are read.
97    ///
98    /// # Safety
99    /// The caller must guarantee that `start_index..start_index + count` is a
100    /// valid range within `buffer` and that `start_index + count` does not
101    /// overflow `usize`.
102    unsafe fn read_exact_unchecked(
103        &mut self,
104        buffer: &mut [u8],
105        start_index: usize,
106        count: usize,
107    ) -> Result<()>;
108
109    /// Reads bytes into a range of `buffer` until that range is full or EOF is
110    /// reached, without checking the range bounds in release builds.
111    ///
112    /// This method has the same EOF and retry behavior as
113    /// [`ReadExt::read_exact_or_eof`], but writes into
114    /// `buffer[start_index..start_index + count]` using raw pointer
115    /// arithmetic.
116    ///
117    /// # Parameters
118    /// - `buffer`: Destination buffer.
119    /// - `start_index`: Start offset inside `buffer`.
120    /// - `count`: Number of bytes to try to read.
121    ///
122    /// # Returns
123    /// The number of bytes written into `buffer[start_index..start_index +
124    /// count]`. The value is in `0..=count`.
125    ///
126    /// # Errors
127    /// Returns the first non-[`ErrorKind::Interrupted`] error reported by the
128    /// underlying reader. Interrupted reads are retried.
129    ///
130    /// # Safety
131    /// The caller must guarantee that `start_index..start_index + count` is a
132    /// valid range within `buffer` and that `start_index + count` does not
133    /// overflow `usize`.
134    unsafe fn read_exact_or_eof_unchecked(
135        &mut self,
136        buffer: &mut [u8],
137        start_index: usize,
138        count: usize,
139    ) -> Result<usize>;
140
141    /// Reads bytes until `buffer` is full or EOF is reached.
142    ///
143    /// This method differs from [`Read::read_exact`] by treating EOF as a
144    /// successful partial result. It keeps retrying short reads until the
145    /// caller-provided buffer is full, EOF is reached, or a non-interrupted
146    /// I/O error occurs.
147    ///
148    /// # Parameters
149    /// - `buffer`: Destination buffer to fill.
150    ///
151    /// # Returns
152    /// The number of bytes written into `buffer`. The value is in
153    /// `0..=buffer.len()`.
154    ///
155    /// # Errors
156    /// Returns the first non-[`ErrorKind::Interrupted`] error reported by the
157    /// underlying reader. Interrupted reads are retried.
158    fn read_exact_or_eof(&mut self, buffer: &mut [u8]) -> Result<usize>;
159
160    /// Reads exactly `N` bytes into a stack-allocated array.
161    ///
162    /// This method uses [`Read::read_exact`] and therefore requires the reader
163    /// to provide exactly `N` bytes before EOF.
164    ///
165    /// # Returns
166    /// An array containing exactly `N` bytes read from this reader.
167    ///
168    /// # Errors
169    /// Returns the error reported by [`Read::read_exact`], including
170    /// [`ErrorKind::UnexpectedEof`] when EOF is reached before the array is
171    /// full.
172    fn read_exact_array<const N: usize>(&mut self) -> Result<[u8; N]>;
173
174    /// Reads exactly `len` bytes into a new vector after checking a limit.
175    ///
176    /// If `len` is greater than `max_len`, this method returns
177    /// [`ErrorKind::InvalidData`] before reading any bytes.
178    ///
179    /// # Parameters
180    /// - `len`: Exact number of bytes to read.
181    /// - `max_len`: Maximum accepted exact read length.
182    ///
183    /// # Returns
184    /// A vector containing exactly `len` bytes.
185    ///
186    /// # Errors
187    /// Returns [`ErrorKind::InvalidData`] when `len > max_len`. Returns the
188    /// error reported by [`Read::read_exact`], including
189    /// [`ErrorKind::UnexpectedEof`] when EOF is reached before `len` bytes are
190    /// read.
191    fn read_exact_vec_limited(
192        &mut self,
193        len: usize,
194        max_len: usize,
195    ) -> Result<Vec<u8>>;
196
197    /// Reads exactly `len` bytes and appends them to `output`.
198    ///
199    /// If `len` is greater than `max_len`, this method returns
200    /// [`ErrorKind::InvalidData`] before reading any bytes and leaves `output`
201    /// unchanged. On a read error, `output` is truncated back to its original
202    /// length. The underlying reader may still have consumed bytes before the
203    /// error because [`Read`] does not provide rollback.
204    ///
205    /// # Parameters
206    /// - `output`: Destination vector to append to.
207    /// - `len`: Exact number of bytes to read.
208    /// - `max_len`: Maximum accepted exact read length.
209    ///
210    /// # Errors
211    /// Returns [`ErrorKind::InvalidData`] when `len > max_len`. Returns the
212    /// error reported by [`Read::read_exact`], including
213    /// [`ErrorKind::UnexpectedEof`] when EOF is reached before `len` bytes are
214    /// read.
215    fn read_exact_vec_limited_into(
216        &mut self,
217        output: &mut Vec<u8>,
218        len: usize,
219        max_len: usize,
220    ) -> Result<()>;
221
222    /// Discards up to `bytes` bytes from this reader.
223    ///
224    /// The method repeatedly reads into an internal stack buffer until the
225    /// requested number of bytes has been consumed or EOF is reached. It does
226    /// not allocate and does not require seeking support.
227    ///
228    /// # Parameters
229    /// - `bytes`: Maximum number of bytes to discard.
230    ///
231    /// # Returns
232    /// The number of bytes actually discarded. The value may be smaller than
233    /// `bytes` when EOF is reached first.
234    ///
235    /// # Errors
236    /// Returns the first non-[`ErrorKind::Interrupted`] error reported by the
237    /// underlying reader. Interrupted reads are retried.
238    fn discard_exact_or_eof(&mut self, bytes: u64) -> Result<u64>;
239
240    /// Copies all remaining bytes from this reader into `writer`.
241    ///
242    /// This method is a method-style wrapper around [`std::io::copy`]. It
243    /// copies from the current reader position until EOF and does not close or
244    /// flush either stream.
245    ///
246    /// # Parameters
247    /// - `writer`: Destination writer.
248    ///
249    /// # Returns
250    /// The number of bytes copied.
251    ///
252    /// # Errors
253    /// Returns the first read or write error reported by the underlying
254    /// streams, using the same error behavior as [`std::io::copy`].
255    fn copy_to(&mut self, writer: &mut dyn Write) -> Result<u64>;
256
257    /// Copies at most `max_bytes` bytes from this reader into `writer`.
258    ///
259    /// This method stops successfully when either EOF is reached or
260    /// `max_bytes` bytes have been copied. It does not close or flush either
261    /// stream.
262    ///
263    /// # Parameters
264    /// - `writer`: Destination writer.
265    /// - `max_bytes`: Maximum number of bytes to copy.
266    ///
267    /// # Returns
268    /// The number of bytes copied.
269    ///
270    /// # Errors
271    /// Returns the first non-[`ErrorKind::Interrupted`] read error or write
272    /// error reported by the underlying streams. Interrupted reads are retried.
273    fn copy_to_at_most(
274        &mut self,
275        writer: &mut dyn Write,
276        max_bytes: u64,
277    ) -> Result<u64>;
278
279    /// Copies the remaining input if its total length is at most `max_bytes`.
280    ///
281    /// This method copies from the current reader position until EOF. If EOF is
282    /// not reached within `max_bytes` bytes, it returns
283    /// [`ErrorKind::InvalidData`]. Detecting oversized input consumes one
284    /// excess byte from this reader; that excess byte is not written to
285    /// `writer`.
286    ///
287    /// # Parameters
288    /// - `writer`: Destination writer.
289    /// - `max_bytes`: Maximum accepted number of bytes in the remaining input.
290    ///
291    /// # Returns
292    /// The number of bytes copied when EOF is reached within the limit.
293    ///
294    /// # Errors
295    /// Returns [`ErrorKind::InvalidData`] when the remaining input is longer
296    /// than `max_bytes`. Returns the first non-[`ErrorKind::Interrupted`] read
297    /// error or write error reported by the underlying streams. Interrupted
298    /// reads are retried.
299    fn copy_to_end_limited(
300        &mut self,
301        writer: &mut dyn Write,
302        max_bytes: u64,
303    ) -> Result<u64>;
304
305    /// Reads the remaining bytes into a vector with a maximum accepted length.
306    ///
307    /// This method consumes bytes from the current reader position until EOF is
308    /// reached. If the stream contains more than `max_len` bytes, it returns
309    /// [`ErrorKind::InvalidData`] after detecting the first excess byte.
310    ///
311    /// # Parameters
312    /// - `max_len`: Maximum number of bytes accepted in the returned vector.
313    ///
314    /// # Returns
315    /// A vector containing all remaining bytes when the stream length is within
316    /// the limit.
317    ///
318    /// # Errors
319    /// Returns [`ErrorKind::InvalidData`] when the stream contains more than
320    /// `max_len` bytes. Returns the first non-[`ErrorKind::Interrupted`] error
321    /// reported by the underlying reader; interrupted reads are retried.
322    fn read_to_end_limited(&mut self, max_len: usize) -> Result<Vec<u8>>;
323
324    /// Reads the remaining bytes into `output` with a maximum accepted length.
325    ///
326    /// This method appends at most `max_len` bytes from the current reader
327    /// position to `output`. If the stream contains more than `max_len` bytes,
328    /// it returns [`ErrorKind::InvalidData`] after detecting the first excess
329    /// byte. In that case, the accepted prefix may already have been appended
330    /// to `output`, and one excess byte may have been consumed from the reader.
331    ///
332    /// # Parameters
333    /// - `output`: Destination vector to append to.
334    /// - `max_len`: Maximum number of bytes accepted from this reader.
335    ///
336    /// # Returns
337    /// The number of bytes appended to `output`.
338    ///
339    /// # Errors
340    /// Returns [`ErrorKind::InvalidData`] when the stream contains more than
341    /// `max_len` bytes. Returns the first non-[`ErrorKind::Interrupted`] error
342    /// reported by the underlying reader; interrupted reads are retried.
343    fn read_to_end_limited_into(
344        &mut self,
345        output: &mut Vec<u8>,
346        max_len: usize,
347    ) -> Result<usize>;
348
349    /// Reads the remaining bytes as UTF-8 text with a maximum accepted length.
350    ///
351    /// This method has the same size limit and read semantics as
352    /// [`ReadExt::read_to_end_limited`], then validates the collected bytes as
353    /// UTF-8.
354    ///
355    /// # Parameters
356    /// - `max_len`: Maximum number of bytes accepted before UTF-8 decoding.
357    ///
358    /// # Returns
359    /// The decoded UTF-8 string.
360    ///
361    /// # Errors
362    /// Returns [`ErrorKind::InvalidData`] when the stream contains more than
363    /// `max_len` bytes or when the collected bytes are not valid UTF-8. Returns
364    /// the first non-[`ErrorKind::Interrupted`] error reported by the
365    /// underlying reader; interrupted reads are retried.
366    fn read_to_string_limited(&mut self, max_len: usize) -> Result<String>;
367
368    /// Reads the remaining bytes as UTF-8 text and appends to `output`.
369    ///
370    /// This method accepts at most `max_len` bytes from the current reader
371    /// position, validates them as UTF-8, and appends the decoded text to
372    /// `output`. If the input is oversized or invalid UTF-8, `output` is left
373    /// unchanged. Oversized input may still consume up to `max_len + 1` bytes
374    /// from the reader while detecting the limit violation.
375    ///
376    /// # Parameters
377    /// - `output`: Destination string to append to.
378    /// - `max_len`: Maximum number of bytes accepted before UTF-8 decoding.
379    ///
380    /// # Returns
381    /// The number of bytes appended to `output`.
382    ///
383    /// # Errors
384    /// Returns [`ErrorKind::InvalidData`] when the stream contains more than
385    /// `max_len` bytes or when the collected bytes are not valid UTF-8. Returns
386    /// the first non-[`ErrorKind::Interrupted`] error reported by the
387    /// underlying reader; interrupted reads are retried.
388    fn read_to_string_limited_into(
389        &mut self,
390        output: &mut String,
391        max_len: usize,
392    ) -> Result<usize>;
393}
394
395impl<T> ReadExt for T
396where
397    T: Read + ?Sized,
398{
399    #[inline(always)]
400    unsafe fn read_unchecked(
401        &mut self,
402        buffer: &mut [u8],
403        start_index: usize,
404        count: usize,
405    ) -> Result<usize> {
406        debug_assert!(
407            start_index
408                .checked_add(count)
409                .is_some_and(|end_index| end_index <= buffer.len()),
410            "unchecked read range exceeds buffer"
411        );
412        // SAFETY: The caller guarantees that the requested range is valid for
413        // `buffer`, and that the computed pointer and length form a valid
414        // mutable subslice of `buffer`.
415        let target = unsafe {
416            core::slice::from_raw_parts_mut(
417                buffer.as_mut_ptr().add(start_index),
418                count,
419            )
420        };
421        self.read(target)
422    }
423
424    unsafe fn read_exact_or_eof_unchecked(
425        &mut self,
426        buffer: &mut [u8],
427        start_index: usize,
428        count: usize,
429    ) -> Result<usize> {
430        debug_assert!(
431            start_index
432                .checked_add(count)
433                .is_some_and(|end_index| end_index <= buffer.len()),
434            "unchecked read range exceeds buffer"
435        );
436        let base = unsafe { buffer.as_mut_ptr().add(start_index) };
437        let mut total = 0;
438        while total < count {
439            // SAFETY: The caller guarantees that `start_index..start_index +
440            // count` is valid for `buffer`; `total < count`, so this remaining
441            // suffix is also a valid mutable subslice.
442            let target = unsafe {
443                core::slice::from_raw_parts_mut(base.add(total), count - total)
444            };
445            match self.read(target) {
446                Ok(0) => break,
447                Ok(read) => total += read,
448                Err(error) => {
449                    if error.kind() == ErrorKind::Interrupted {
450                        continue;
451                    }
452                    return Err(error);
453                }
454            }
455        }
456        Ok(total)
457    }
458
459    unsafe fn read_exact_unchecked(
460        &mut self,
461        buffer: &mut [u8],
462        start_index: usize,
463        count: usize,
464    ) -> Result<()> {
465        debug_assert!(
466            start_index
467                .checked_add(count)
468                .is_some_and(|end_index| end_index <= buffer.len()),
469            "unchecked read range exceeds buffer"
470        );
471        // SAFETY: The caller guarantees that the requested range is valid for
472        // `buffer`, and that the computed pointer and length form a valid
473        // mutable subslice of `buffer`.
474        let target = unsafe {
475            core::slice::from_raw_parts_mut(
476                buffer.as_mut_ptr().add(start_index),
477                count,
478            )
479        };
480        self.read_exact(target)
481    }
482
483    fn read_exact_or_eof(&mut self, buffer: &mut [u8]) -> Result<usize> {
484        let mut total = 0;
485        while total < buffer.len() {
486            match self.read(&mut buffer[total..]) {
487                Ok(0) => break,
488                Ok(count) => total += count,
489                Err(error) => {
490                    if error.kind() == ErrorKind::Interrupted {
491                        continue;
492                    }
493                    return Err(error);
494                }
495            }
496        }
497        Ok(total)
498    }
499
500    #[inline(always)]
501    fn read_exact_array<const N: usize>(&mut self) -> Result<[u8; N]> {
502        let mut buffer = [0; N];
503        self.read_exact(&mut buffer)?;
504        Ok(buffer)
505    }
506
507    fn read_exact_vec_limited(
508        &mut self,
509        len: usize,
510        max_len: usize,
511    ) -> Result<Vec<u8>> {
512        validate_exact_read_len(len, max_len)?;
513        let mut output = Vec::new();
514        let mut reader = self;
515        read_exact_vec_limited_into_impl(
516            &mut reader,
517            &mut output,
518            len,
519            max_len,
520        )?;
521        Ok(output)
522    }
523
524    #[inline(always)]
525    fn read_exact_vec_limited_into(
526        &mut self,
527        output: &mut Vec<u8>,
528        len: usize,
529        max_len: usize,
530    ) -> Result<()> {
531        let mut reader = self;
532        read_exact_vec_limited_into_impl(&mut reader, output, len, max_len)
533    }
534
535    fn discard_exact_or_eof(&mut self, bytes: u64) -> Result<u64> {
536        let mut buffer = [0; DISCARD_BUFFER_SIZE];
537        let mut remaining = bytes;
538        let mut discarded = 0;
539        while remaining > 0 {
540            let requested = remaining.min(DISCARD_BUFFER_SIZE as u64) as usize;
541            match self.read(&mut buffer[..requested]) {
542                Ok(0) => break,
543                Ok(count) => {
544                    let count = count as u64;
545                    remaining -= count;
546                    discarded += count;
547                }
548                Err(error) => {
549                    if error.kind() == ErrorKind::Interrupted {
550                        continue;
551                    }
552                    return Err(error);
553                }
554            }
555        }
556        Ok(discarded)
557    }
558
559    #[inline(always)]
560    fn copy_to(&mut self, writer: &mut dyn Write) -> Result<u64> {
561        copy_all(self, writer)
562    }
563
564    #[inline(always)]
565    fn copy_to_at_most(
566        &mut self,
567        writer: &mut dyn Write,
568        max_bytes: u64,
569    ) -> Result<u64> {
570        let mut reader = self;
571        Streams::copy_at_most(&mut reader, writer, max_bytes)
572    }
573
574    #[inline(always)]
575    fn copy_to_end_limited(
576        &mut self,
577        writer: &mut dyn Write,
578        max_bytes: u64,
579    ) -> Result<u64> {
580        let mut reader = self;
581        Streams::copy_to_end_limited(&mut reader, writer, max_bytes)
582    }
583
584    #[inline(always)]
585    fn read_to_end_limited(&mut self, max_len: usize) -> Result<Vec<u8>> {
586        let mut reader = self;
587        read_to_end_limited_impl(&mut reader, max_len)
588    }
589
590    #[inline(always)]
591    fn read_to_end_limited_into(
592        &mut self,
593        output: &mut Vec<u8>,
594        max_len: usize,
595    ) -> Result<usize> {
596        let mut reader = self;
597        read_to_end_limited_into_impl(&mut reader, output, max_len)
598    }
599
600    fn read_to_string_limited(&mut self, max_len: usize) -> Result<String> {
601        let mut reader = self;
602        let bytes = read_to_end_limited_impl(&mut reader, max_len)?;
603        String::from_utf8(bytes).map_err(invalid_utf8_error)
604    }
605
606    fn read_to_string_limited_into(
607        &mut self,
608        output: &mut String,
609        max_len: usize,
610    ) -> Result<usize> {
611        let mut reader = self;
612        let bytes = read_to_end_limited_impl(&mut reader, max_len)?;
613        let text = String::from_utf8(bytes).map_err(invalid_utf8_error)?;
614        let count = text.len();
615        try_reserve_string(output, count)?;
616        output.push_str(&text);
617        Ok(count)
618    }
619}
620
621/// Reads exactly `len` bytes from `reader` and appends them to `output`.
622///
623/// # Parameters
624/// - `reader`: Source reader.
625/// - `output`: Destination vector to append to.
626/// - `len`: Exact number of bytes to read.
627/// - `max_len`: Maximum accepted exact read length.
628///
629/// # Errors
630/// Returns [`ErrorKind::InvalidData`] when `len > max_len` before reading and
631/// leaves `output` unchanged. Returns the error reported by
632/// [`Read::read_exact`] for read failures and truncates `output` back to its
633/// original length.
634fn read_exact_vec_limited_into_impl(
635    reader: &mut dyn Read,
636    output: &mut Vec<u8>,
637    len: usize,
638    max_len: usize,
639) -> Result<()> {
640    validate_exact_read_len(len, max_len)?;
641    let original_len = output.len();
642    let new_len = match original_len.checked_add(len) {
643        Some(value) => value,
644        None => {
645            return Err(Error::new(
646                ErrorKind::InvalidInput,
647                format!("length {original_len} plus {len} overflows usize"),
648            ));
649        }
650    };
651    try_reserve_vec(output, len)?;
652    output.resize(new_len, 0);
653    match reader.read_exact(&mut output[original_len..]) {
654        Ok(()) => Ok(()),
655        Err(error) => {
656            output.truncate(original_len);
657            Err(error)
658        }
659    }
660}
661
662/// Validates that an exact read length is within the configured maximum.
663///
664/// # Parameters
665/// - `len`: Exact number of bytes requested by the caller.
666/// - `max_len`: Maximum accepted exact read length.
667///
668/// # Errors
669/// Returns [`ErrorKind::InvalidData`] when `len > max_len`.
670#[inline(always)]
671fn validate_exact_read_len(len: usize, max_len: usize) -> Result<()> {
672    if len > max_len {
673        return Err(Error::new(
674            ErrorKind::InvalidData,
675            format!("requested length {len} exceeds maximum length {max_len}"),
676        ));
677    }
678    Ok(())
679}
680
681/// Reads all remaining bytes from `reader` when the result fits `max_len`.
682///
683/// # Parameters
684/// - `reader`: Source reader.
685/// - `max_len`: Maximum accepted result length.
686///
687/// # Returns
688/// A vector containing all remaining bytes.
689///
690/// # Errors
691/// Returns [`ErrorKind::InvalidData`] after detecting that the input contains
692/// more than `max_len` bytes. Returns the first non-interrupted read error
693/// reported by `reader`.
694fn read_to_end_limited_impl(
695    reader: &mut dyn Read,
696    max_len: usize,
697) -> Result<Vec<u8>> {
698    let mut output = Vec::new();
699    try_reserve_vec(&mut output, max_len.min(READ_TO_END_BUFFER_SIZE))?;
700    read_to_end_limited_into_impl(reader, &mut output, max_len)?;
701    Ok(output)
702}
703
704/// Reads all remaining bytes from `reader` into `output` when the input fits.
705///
706/// # Parameters
707/// - `reader`: Source reader.
708/// - `output`: Destination vector to append to.
709/// - `max_len`: Maximum accepted input length in bytes.
710///
711/// # Returns
712/// The number of bytes appended to `output`.
713///
714/// # Errors
715/// Returns [`ErrorKind::InvalidData`] after detecting that the input contains
716/// more than `max_len` bytes. Returns the first non-interrupted read error
717/// reported by `reader`.
718fn read_to_end_limited_into_impl(
719    reader: &mut dyn Read,
720    output: &mut Vec<u8>,
721    max_len: usize,
722) -> Result<usize> {
723    let mut buffer = [0; READ_TO_END_BUFFER_SIZE];
724    let mut appended = 0;
725    loop {
726        let remaining = max_len.saturating_sub(appended);
727        let requested =
728            remaining.saturating_add(1).min(READ_TO_END_BUFFER_SIZE);
729        match reader.read(&mut buffer[..requested]) {
730            Ok(0) => return Ok(appended),
731            Ok(count) if count <= remaining => {
732                try_reserve_vec(output, count)?;
733                output.extend_from_slice(&buffer[..count]);
734                appended += count;
735            }
736            Ok(_) => {
737                if remaining > 0 {
738                    try_reserve_vec(output, remaining)?;
739                    output.extend_from_slice(&buffer[..remaining]);
740                }
741                return Err(Error::new(
742                    ErrorKind::InvalidData,
743                    format!("input exceeds maximum length of {max_len} bytes"),
744                ));
745            }
746            Err(error) => {
747                if error.kind() == ErrorKind::Interrupted {
748                    continue;
749                }
750                return Err(error);
751            }
752        }
753    }
754}
755
756/// Converts an invalid UTF-8 read result into an I/O error.
757///
758/// # Parameters
759/// - `error`: UTF-8 conversion error.
760///
761/// # Returns
762/// An [`ErrorKind::InvalidData`] error containing the UTF-8 error context.
763fn invalid_utf8_error(error: FromUtf8Error) -> Error {
764    Error::new(
765        ErrorKind::InvalidData,
766        format!("limited input is not valid UTF-8: {error}"),
767    )
768}