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}