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}