Skip to main content

qubit_io/ext/
read_ext.rs

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