qubit_codec/transcode/io/transcode_decode_input.rs
1// =============================================================================
2// Copyright (c) 2026 Haixing Hu.
3//
4// SPDX-License-Identifier: Apache-2.0
5//
6// Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! Buffered input driver that decodes units into values.
9
10use core::fmt::Debug;
11use core::fmt::Formatter;
12use core::fmt::Result as FormatResult;
13use std::collections::TryReserveError;
14use std::io::Error;
15use std::io::ErrorKind;
16use std::io::Read;
17use std::io::Result;
18use std::io::Seek;
19use std::io::SeekFrom;
20use std::result::Result as StdResult;
21
22use qubit_io::Buffer;
23use qubit_io::BufferedInput;
24use qubit_io::ByteInput;
25use qubit_io::Input;
26use qubit_io::SeekableByteInput;
27use qubit_utils::SliceRange;
28use qubit_utils::UncheckedSlice;
29use qubit_utils::allocation_error;
30use qubit_utils::try_reserve_vec;
31
32use super::internal::CodecDecodeDriver;
33use super::internal::capacity_error_to_invalid_data;
34use super::internal::validate_decode_progress;
35use super::internal::validate_eof_decode_progress;
36use crate::Codec;
37use crate::DecodeLifecycleOutput;
38use crate::DecodeLifecycleProgress;
39use crate::TranscodeDomainError;
40use crate::TranscodeFailure;
41use crate::TranscodeProgress;
42use crate::TranscodeStatus;
43use crate::Transcoder;
44use crate::codec::assert_unit_bounds;
45
46/// Decodes an [`Input`] unit stream into an [`Input`] value stream.
47///
48/// This type owns only the unit-level [`qubit_io::BufferedInput`]. Callers pass
49/// a streaming [`Transcoder`] and error mapper to each decode operation, which
50/// lets one buffered input drive different decoders without nesting buffers or
51/// storing decoder-specific state in the buffer owner.
52///
53/// # Type Parameters
54///
55/// * `I` - Wrapped unit input.
56///
57/// # Examples
58///
59/// ```
60/// use core::convert::Infallible;
61/// use core::num::NonZeroUsize;
62/// use std::io::Cursor;
63/// use qubit_codec::Codec;
64/// use qubit_codec::DecodeFailure;
65/// use qubit_codec::TranscodeDecodeInput;
66///
67/// struct Identity;
68/// impl Codec for Identity {
69/// type Value = u8;
70/// type Unit = u8;
71/// type DecodeError = Infallible;
72/// type EncodeError = Infallible;
73/// const MIN_UNITS_PER_VALUE: usize = 1;
74/// const MAX_DECODE_UNITS_PER_VALUE: usize = 1;
75/// const MAX_ENCODE_UNITS_PER_VALUE: usize = 1;
76/// unsafe fn decode(&mut self, input: &[u8], index: usize)
77/// -> Result<(u8, NonZeroUsize), DecodeFailure<Infallible>> {
78/// Ok((input[index], NonZeroUsize::MIN))
79/// }
80/// unsafe fn encode(&mut self, value: &u8, output: &mut [u8], index: usize)
81/// -> Result<usize, Infallible> {
82/// output[index] = *value;
83/// Ok(1)
84/// }
85/// }
86///
87/// let mut input = TranscodeDecodeInput::with_capacity(Cursor::new(vec![42_u8]), 8);
88/// assert!(input.fill_until(1).expect("refilling the cursor input should succeed"));
89/// assert_eq!(input.unread(), &[42]);
90/// let value = input.read_decoded_with(&mut Identity, |error| match error {})?;
91/// assert_eq!(value, 42);
92/// # Ok::<(), std::io::Error>(())
93/// ```
94///
95/// `read_decoded_with` reads one complete value and owns its strict
96/// single-value lifecycle; use the step methods when the caller needs to
97/// coordinate streaming input and output itself.
98pub struct TranscodeDecodeInput<I>
99where
100 I: Input,
101 I::Item: Copy + Default,
102{
103 /// Owns the unit source and retains unread units across decode operations.
104 input: BufferedInput<I>,
105 /// Tracks an EOF call that stopped for output capacity and must be resumed.
106 eof_retry_pending: bool,
107}
108
109impl<I> TranscodeDecodeInput<I>
110where
111 I: Input,
112 I::Item: Copy + Default,
113{
114 /// Creates a decoder input with the default unit buffer capacity.
115 ///
116 /// # Parameters
117 ///
118 /// * `inner` - Unit input read by this adapter.
119 ///
120 /// # Returns
121 ///
122 /// A new buffered decoder input.
123 ///
124 /// # Panics
125 ///
126 /// Panics if `I::Item::default()` panics or the default buffer capacity
127 /// exceeds the supported allocation size.
128 #[must_use]
129 #[inline]
130 pub fn new(inner: I) -> Self {
131 Self {
132 input: BufferedInput::new(inner),
133 eof_retry_pending: false,
134 }
135 }
136
137 /// Creates a decoder input with a unit buffer of at least `capacity`.
138 ///
139 /// # Parameters
140 ///
141 /// * `inner` - Unit input read by this adapter.
142 /// * `capacity` - Requested internal unit buffer capacity.
143 ///
144 /// # Returns
145 ///
146 /// A new buffered decoder input.
147 ///
148 /// # Panics
149 ///
150 /// Panics if `I::Item::default()` panics or the requested capacity exceeds
151 /// the supported allocation size.
152 #[must_use]
153 #[inline]
154 pub fn with_capacity(inner: I, capacity: usize) -> Self {
155 Self {
156 input: BufferedInput::with_capacity(inner, capacity),
157 eof_retry_pending: false,
158 }
159 }
160
161 /// Creates a decoder input with a unit buffer of at least `capacity`.
162 ///
163 /// # Parameters
164 ///
165 /// * `inner` - Unit input read by this adapter.
166 /// * `capacity` - Requested internal unit buffer capacity.
167 ///
168 /// # Returns
169 ///
170 /// Returns a buffered adapter owning `inner` with at least the requested
171 /// capacity.
172 ///
173 /// # Errors
174 ///
175 /// Returns an allocation error when the requested buffer cannot be
176 /// allocated.
177 ///
178 /// # Panics
179 ///
180 /// Panics if `I::Item::default()` panics while initializing the buffer.
181 pub fn try_with_capacity(inner: I, capacity: usize) -> StdResult<Self, TryReserveError> {
182 Ok(Self {
183 input: BufferedInput::try_with_capacity(inner, capacity)?,
184 eof_retry_pending: false,
185 })
186 }
187
188 /// Returns a shared reference to the wrapped unit input.
189 ///
190 /// The wrapped input can be physically positioned after units that remain
191 /// unread in this adapter's internal buffer.
192 ///
193 /// # Returns
194 ///
195 /// A shared reference to the wrapped unit input.
196 #[must_use]
197 #[inline]
198 pub const fn inner(&self) -> &I {
199 self.input.inner()
200 }
201
202 /// Returns the number of unread units currently buffered.
203 ///
204 /// # Returns
205 ///
206 /// The number of unread units in the internal buffer.
207 #[must_use]
208 #[inline]
209 pub fn unread_len(&self) -> usize {
210 self.input.unread_len()
211 }
212
213 /// Returns the currently buffered unread units.
214 ///
215 /// # Returns
216 ///
217 /// Returns a shared slice over the unread portion of the internal unit
218 /// buffer. The slice is valid until this adapter is mutated.
219 #[must_use]
220 #[inline]
221 pub fn unread(&self) -> &[I::Item] {
222 self.input.unread()
223 }
224
225 /// Returns the internal unit buffer capacity.
226 ///
227 /// # Returns
228 ///
229 /// The maximum number of units retained in the internal buffer.
230 #[must_use]
231 #[inline]
232 pub fn capacity(&self) -> usize {
233 self.input.capacity()
234 }
235
236 /// Refills the internal buffer until at least `count` unread units are
237 /// available.
238 ///
239 /// # Parameters
240 ///
241 /// * `count` - Minimum number of unread units required.
242 ///
243 /// # Returns
244 ///
245 /// Returns `true` when at least `count` units are buffered; `false` if EOF
246 /// prevents reaching that count. Buffered units remain available in either
247 /// case.
248 ///
249 /// # Errors
250 ///
251 /// Returns allocation errors mapped to [`ErrorKind::OutOfMemory`], or I/O
252 /// errors from the wrapped input while refilling.
253 pub fn fill_until(&mut self, count: usize) -> Result<bool> {
254 if count > self.input.capacity() {
255 self.input.try_reserve_capacity(count).map_err(allocation_error)?;
256 }
257 let previous_unread = self.input.unread_len();
258 let result = self.input.fill_until(count);
259 if self.input.unread_len() > previous_unread {
260 self.eof_retry_pending = false;
261 }
262 result
263 }
264
265 /// Performs one decode step and preserves the transcoder stop status.
266 ///
267 /// `None` means that the wrapped input reached EOF with no buffered units.
268 /// Consumed input is committed before this method returns. Callers can use
269 /// the returned [`TranscodeProgress`] to distinguish `NeedOutput` from an
270 /// incomplete input tail without guessing from the unread buffer alone.
271 ///
272 /// # Type Parameters
273 ///
274 /// - `D`: Streaming decoder accepting the source unit type.
275 /// - `M`: Mapper from decoder errors to I/O errors.
276 /// - `Value`: Decoded destination value type.
277 ///
278 /// # Parameters
279 ///
280 /// - `decoder`: Decoder for the current logical stream.
281 /// - `map_error`: Mapper invoked for decoder errors.
282 /// - `output`: Destination value storage.
283 /// - `output_index`: Start of the writable range.
284 /// - `count`: Maximum number of destination values available.
285 ///
286 /// # Returns
287 ///
288 /// Returns `Some` validated progress after a decode step, or `None` at EOF
289 /// with no buffered units. A zero count returns `Some` zero progress.
290 ///
291 /// # Errors
292 ///
293 /// Returns invalid output-range or progress errors, input/refill errors,
294 /// or decoder errors translated by `map_error`.
295 /// A successful validated progress commits its `read()` count. If decoding
296 /// or progress validation fails, this call does not consume the unread
297 /// range. The decoder and destination may already have changed; neither is
298 /// rolled back, and no complete progress report is available. A refill
299 /// performed before the failure is not rolled back at the wrapped input.
300 /// Do not replay the original input unless the decoder defines an explicit
301 /// recovery protocol.
302 pub fn transcode_step<D, M, Value>(
303 &mut self,
304 decoder: &mut D,
305 map_error: &mut M,
306 output: &mut [Value],
307 output_index: usize,
308 count: usize,
309 ) -> Result<Option<TranscodeProgress>>
310 where
311 D: Transcoder<Input = I::Item, Output = Value>,
312 M: FnMut(D::Error) -> Error,
313 {
314 let output_end = SliceRange::checked_range_end(
315 output.len(),
316 output_index,
317 count,
318 "decoded output range exceeds destination buffer",
319 )?;
320 if count == 0 {
321 return Ok(Some(TranscodeProgress::complete(0, 0)));
322 }
323 if self.unread_len() == 0 && !self.fill_more()? {
324 return Ok(None);
325 }
326 let available_input = self.unread_len();
327 let progress = decoder
328 .transcode(self.unread(), 0, &mut output[..output_end], output_index)
329 .map_err(&mut *map_error)
330 .and_then(|progress| validate_decode_progress(progress, 0, available_input, output_index, count))?;
331 self.consume(progress.read());
332 Ok(Some(progress))
333 }
334
335 /// Performs one decode step after the caller has established EOF.
336 ///
337 /// This method does not read from the wrapped input. It passes the current
338 /// unread buffer to [`Transcoder::transcode_eof`], validates the returned
339 /// progress, and commits consumed source units before returning.
340 ///
341 /// # Type Parameters
342 ///
343 /// - `D`: Streaming decoder accepting the source unit type.
344 /// - `M`: Mapper from decoder errors to I/O errors.
345 /// - `Value`: Decoded destination value type.
346 ///
347 /// # Parameters
348 ///
349 /// - `decoder`: Decoder for the current logical stream.
350 /// - `map_error`: Mapper invoked for decoder errors.
351 /// - `output`: Destination value storage.
352 /// - `output_index`: Start of the writable range.
353 /// - `count`: Maximum number of destination values available.
354 ///
355 /// # Returns
356 ///
357 /// Returns validated EOF progress. A zero output count returns zero
358 /// progress without calling the decoder; an empty input is still passed to
359 /// `transcode_eof` so decoders can handle EOF with retained state.
360 ///
361 /// # Errors
362 ///
363 /// Returns invalid output-range errors, decoder errors mapped by
364 /// `map_error`, or `InvalidData` if the decoder requests more input after
365 /// EOF. Invalid progress does not commit source consumption, but decoder
366 /// state and caller-owned output are not rolled back.
367 pub fn transcode_eof_step<D, M, Value>(
368 &mut self,
369 decoder: &mut D,
370 map_error: &mut M,
371 output: &mut [Value],
372 output_index: usize,
373 count: usize,
374 ) -> Result<TranscodeProgress>
375 where
376 D: Transcoder<Input = I::Item, Output = Value>,
377 M: FnMut(D::Error) -> Error,
378 {
379 let output_end = SliceRange::checked_range_end(
380 output.len(),
381 output_index,
382 count,
383 "decoded EOF output range exceeds destination buffer",
384 )?;
385 if count == 0 {
386 return Ok(TranscodeProgress::complete(0, 0));
387 }
388 let available_input = self.unread_len();
389 let progress = decoder
390 .transcode_eof(self.unread(), 0, &mut output[..output_end], output_index)
391 .map_err(&mut *map_error)
392 .and_then(|progress| validate_eof_decode_progress(progress, 0, available_input, output_index, count))?;
393 self.consume(progress.read());
394 self.eof_retry_pending = matches!(progress.status(), TranscodeStatus::NeedOutput { .. });
395 Ok(progress)
396 }
397
398 /// Consumes unread units from the current buffer window.
399 ///
400 /// # Parameters
401 ///
402 /// * `count` - Number of unread units to discard.
403 ///
404 /// # Panics
405 ///
406 /// Panics when `count` exceeds [`Self::unread_len`].
407 #[inline]
408 pub fn consume(&mut self, count: usize) {
409 assert!(count <= self.unread_len(), "cannot consume beyond buffered input",);
410 // SAFETY: The caller-provided count is within the unread window.
411 unsafe {
412 self.input.consume(count);
413 }
414 }
415
416 /// Copies unread units into an indexed output range without consuming them.
417 ///
418 /// # Parameters
419 ///
420 /// * `output` - Destination storage that receives a copy of unread units.
421 /// * `output_index` - Start index inside `output`.
422 /// * `count` - Number of unread units to copy.
423 ///
424 /// # Safety
425 ///
426 /// The caller must guarantee that `output_index..output_index + count` is
427 /// a valid range inside `output`, that the addition does not overflow, that
428 /// `count <= self.unread_len()`, and that the destination range does not
429 /// overlap with the unread units stored inside this buffer.
430 pub unsafe fn copy_unread_to(&self, output: &mut [I::Item], output_index: usize, count: usize) {
431 // SAFETY: The caller guarantees the destination range and non-overlap
432 // requirements for the unread copy.
433 let unread = self.unread();
434 unsafe {
435 UncheckedSlice::copy_nonoverlapping(unread, 0, output, output_index, count);
436 }
437 }
438
439 /// Consumes this adapter and returns its parts.
440 ///
441 /// # Returns
442 ///
443 /// The wrapped input and the buffer holding unread units.
444 #[must_use = "the returned input and unread buffer must be handled"]
445 #[inline]
446 pub fn into_parts(self) -> (I, Buffer<I::Item>) {
447 self.input.into_parts()
448 }
449
450 /// Reads buffered units into an indexed output range.
451 ///
452 /// # Parameters
453 ///
454 /// * `output` - Destination unit storage.
455 /// * `output_index` - Start index inside `output`.
456 /// * `count` - Maximum number of units to read.
457 ///
458 /// # Returns
459 ///
460 /// The number of units copied into `output`.
461 ///
462 /// # Errors
463 ///
464 /// Returns input or buffer validation errors from the wrapped
465 /// [`qubit_io::BufferedInput`].
466 ///
467 /// # Panics
468 ///
469 /// Debug builds panic if the destination range violates the safety
470 /// contract.
471 ///
472 /// # Safety
473 ///
474 /// The caller must guarantee that `output_index..output_index + count` is
475 /// a valid range inside `output` and that the addition does not overflow.
476 pub unsafe fn read_unchecked(
477 &mut self,
478 output: &mut [I::Item],
479 output_index: usize,
480 count: usize,
481 ) -> Result<usize> {
482 debug_assert!(
483 SliceRange::range_fits(output.len(), output_index, count),
484 "unchecked read output range exceeds destination buffer",
485 );
486 if count == 0 {
487 return Ok(0);
488 }
489 self.eof_retry_pending = false;
490 // SAFETY: The caller guarantees the destination range is valid.
491 unsafe { self.input.read_unchecked(output, output_index, count) }
492 }
493
494 /// Decodes one codec value from the buffered unit input.
495 ///
496 /// This strict convenience method supports codecs whose decode reset and
497 /// finish phases do not emit values. Use
498 /// [`Self::read_decoded_lifecycle_with`] when those phases have output.
499 ///
500 /// # Type Parameters
501 ///
502 /// - `C`: Codec accepting the wrapped input's unit type.
503 /// - `M`: Mapper from codec decode errors to I/O errors.
504 ///
505 /// # Parameters
506 ///
507 /// * `codec` - Codec used for this single-value decode.
508 /// * `map_error` - Mapper for codec-domain invalid-input errors.
509 ///
510 /// # Returns
511 ///
512 /// Returns one decoded codec value.
513 ///
514 /// # Errors
515 ///
516 /// Returns [`ErrorKind::Unsupported`] before invoking the codec or reading
517 /// input when reset or finish may emit values. Otherwise, returns I/O
518 /// errors from the wrapped input, `UnexpectedEof` when EOF occurs before a
519 /// complete value is available, `InvalidData` when the codec reports an
520 /// impossible incomplete state, or a mapped codec-domain error for reset,
521 /// invalid input, or finish failures. Each mapped error owns a
522 /// [`TranscodeDomainError`] identifying the phase; main decode errors use
523 /// index `0`, the start of this single-value input window. The mapper's
524 /// error remains the wrapper source, preserving its kind and payload.
525 ///
526 /// This operation is not transactional. A successful main decode consumes
527 /// its source units before codec finalization. If finalization fails, the
528 /// decoded value is not returned and the consumed input is not restored.
529 /// A later read must not be treated as a retry of that value. Truncated
530 /// input at EOF is consumed before reporting the error. Invalid-input
531 /// consumption follows the codec's validated consumption hint. Codec
532 /// state is not rolled back. The `Unsupported` preflight error above is
533 /// returned before invoking the codec or reading input.
534 ///
535 /// # Panics
536 ///
537 /// Panics when the codec reports more reset or finish values than its
538 /// declared bounds.
539 pub fn read_decoded_with<C, M>(&mut self, codec: &mut C, map_error: M) -> Result<C::Value>
540 where
541 C: Codec<Unit = I::Item>,
542 M: FnMut(C::DecodeError) -> Error,
543 {
544 TranscodeFailure::ensure_no_decode_lifecycle_output::<C>()
545 .map_err(|error| Error::new(ErrorKind::Unsupported, error))?;
546 let progress = self.read_decoded_lifecycle_with_scratch_impl(codec, &mut [], &mut [], map_error)?;
547 let (value, reset_written, finish_written) = progress.into_parts();
548 debug_assert_eq!(0, reset_written);
549 debug_assert_eq!(0, finish_written);
550 Ok(value)
551 }
552
553 /// Decodes one complete codec lifecycle and preserves every output phase.
554 ///
555 /// The method allocates independent storage for values emitted by
556 /// `decode_reset` and `decode_finish`, so neither phase can overwrite the
557 /// other.
558 ///
559 /// # Type Parameters
560 ///
561 /// - `C`: Codec accepting the wrapped input's unit type.
562 /// - `M`: Mapper from codec decode errors to I/O errors.
563 ///
564 /// # Parameters
565 ///
566 /// - `codec`: Codec used to decode one complete lifecycle.
567 /// - `map_error`: Maps codec decode errors to I/O errors.
568 ///
569 /// # Returns
570 ///
571 /// Returns reset output, the main decoded value, and finish output.
572 ///
573 /// # Errors
574 ///
575 /// Returns I/O errors from the wrapped input, `UnexpectedEof` when EOF
576 /// occurs before a complete value is available, `InvalidData` when the
577 /// codec reports an impossible incomplete state, or a mapped codec-domain
578 /// error for reset, invalid input, or finish failures. Each mapped error
579 /// owns a [`TranscodeDomainError`] identifying the phase; main decode
580 /// errors use index `0`, the start of this input window. The mapper's error
581 /// remains the wrapper source, preserving its kind and payload.
582 /// Returns `OutOfMemory` when lifecycle output storage cannot be reserved.
583 ///
584 /// This operation is not transactional. A successful main decode consumes
585 /// its source units before codec finalization. If finalization fails, the
586 /// decoded value is not returned and the consumed input is not restored.
587 /// A later read must not be treated as a retry of that value. Truncated
588 /// input at EOF is consumed before reporting the error. Invalid-input
589 /// consumption follows the codec's validated consumption hint. Codec
590 /// state is not rolled back.
591 ///
592 /// # Panics
593 ///
594 /// Panics when the codec reports more reset or finish values than its
595 /// declared bounds.
596 pub fn read_decoded_lifecycle_with<C, M>(
597 &mut self,
598 codec: &mut C,
599 map_error: M,
600 ) -> Result<DecodeLifecycleOutput<C::Value>>
601 where
602 C: Codec<Unit = I::Item>,
603 C::Value: Default,
604 M: FnMut(C::DecodeError) -> Error,
605 {
606 assert_unit_bounds::<C>();
607 let mut reset_output = Vec::new();
608 try_reserve_vec(&mut reset_output, C::MAX_DECODE_RESET_VALUES).map_err(allocation_error)?;
609 reset_output.resize_with(C::MAX_DECODE_RESET_VALUES, C::Value::default);
610 let mut finish_output = Vec::new();
611 try_reserve_vec(&mut finish_output, C::MAX_DECODE_FINISH_VALUES).map_err(allocation_error)?;
612 finish_output.resize_with(C::MAX_DECODE_FINISH_VALUES, C::Value::default);
613 let progress =
614 self.read_decoded_lifecycle_with_scratch_impl(codec, &mut reset_output, &mut finish_output, map_error)?;
615 let (value, reset_written, finish_written) = progress.into_parts();
616 reset_output.truncate(reset_written);
617 finish_output.truncate(finish_written);
618 Ok(DecodeLifecycleOutput::new(reset_output, value, finish_output))
619 }
620
621 /// Decodes one complete codec lifecycle into separate caller storage.
622 ///
623 /// # Type Parameters
624 ///
625 /// - `C`: Codec accepting the wrapped input's unit type.
626 /// - `M`: Mapper from codec decode errors to I/O errors.
627 ///
628 /// # Parameters
629 ///
630 /// - `codec`: Codec used to decode one complete lifecycle.
631 /// - `reset_output`: Reusable storage for values emitted by
632 /// [`Codec::decode_reset`].
633 /// - `finish_output`: Reusable storage for values emitted by
634 /// [`Codec::decode_finish`].
635 /// - `map_error`: Maps codec decode errors to I/O errors.
636 ///
637 /// # Returns
638 ///
639 /// Returns the main decoded value and the initialized lengths of both
640 /// lifecycle output buffers.
641 ///
642 /// # Errors
643 ///
644 /// Returns [`ErrorKind::InvalidInput`] when either output buffer is shorter
645 /// than the corresponding codec bound. Returns I/O errors from the wrapped
646 /// input, `UnexpectedEof` when EOF occurs before a complete value is
647 /// available, `InvalidData` when the codec reports an impossible
648 /// incomplete state, or a mapped codec-domain error for reset, invalid
649 /// input, or finish failures. Each mapped error owns a
650 /// [`TranscodeDomainError`] identifying the phase; main decode errors use
651 /// index `0`, the start of this input window. The mapper's error remains
652 /// the wrapper source, preserving its kind and payload.
653 ///
654 /// This operation is not transactional. A successful main decode consumes
655 /// its source units before codec finalization. If finalization fails, the
656 /// decoded value is not returned and the consumed input is not restored.
657 /// A later read must not be treated as a retry of that value. Truncated
658 /// input at EOF is consumed before reporting the error. Invalid-input
659 /// consumption follows the codec's validated consumption hint. Codec
660 /// state is not rolled back. A short scratch buffer is rejected before
661 /// invoking the codec or reading input. Reset and finish output buffers
662 /// may already have changed when an error is returned; the error carries
663 /// no valid output lengths, so their full contents must not be treated as
664 /// this operation's successful output. Recovery of codec state after an
665 /// error is codec-specific, and consumed input is never restored.
666 ///
667 /// # Panics
668 ///
669 /// Panics when the codec reports more reset or finish values than its
670 /// declared bounds.
671 pub fn read_decoded_lifecycle_with_scratch<C, M>(
672 &mut self,
673 codec: &mut C,
674 reset_output: &mut [C::Value],
675 finish_output: &mut [C::Value],
676 map_error: M,
677 ) -> Result<DecodeLifecycleProgress<C::Value>>
678 where
679 C: Codec<Unit = I::Item>,
680 M: FnMut(C::DecodeError) -> Error,
681 {
682 self.read_decoded_lifecycle_with_scratch_impl(codec, reset_output, finish_output, map_error)
683 }
684
685 /// Runs decoder reset into an indexed output range.
686 ///
687 /// This method does not read or consume buffered input units.
688 ///
689 /// # Type Parameters
690 ///
691 /// - `D`: Streaming decoder accepting the source unit type.
692 /// - `M`: Mapper from decoder errors to I/O errors.
693 /// - `Value`: Decoded destination value type.
694 ///
695 /// # Parameters
696 ///
697 /// - `decoder`: Decoder for the current logical stream.
698 /// - `map_error`: Mapper invoked for decoder errors.
699 /// - `output`: Destination value storage.
700 /// - `output_index`: Start of the writable range.
701 /// - `count`: Maximum number of destination values available.
702 ///
703 /// # Returns
704 ///
705 /// Returns the number of reset values initialized in the requested range.
706 ///
707 /// # Errors
708 ///
709 /// Returns invalid output ranges, insufficient declared output capacity,
710 /// capacity errors, or reset errors mapped by `map_error`.
711 ///
712 /// # Panics
713 ///
714 /// Panics when the decoder reports writing more values than its declared
715 /// reset bound.
716 pub fn reset<D, M, Value>(
717 &self,
718 decoder: &mut D,
719 map_error: &mut M,
720 output: &mut [Value],
721 output_index: usize,
722 count: usize,
723 ) -> Result<usize>
724 where
725 D: Transcoder<Input = I::Item, Output = Value>,
726 M: FnMut(D::Error) -> Error,
727 {
728 let required = decoder.max_reset_output_len().map_err(capacity_error_to_invalid_data)?;
729 let output_end = SliceRange::checked_range_end(
730 output.len(),
731 output_index,
732 count,
733 "reset output range exceeds destination buffer",
734 )?;
735 if count < required {
736 return Err(Error::new(
737 ErrorKind::InvalidData,
738 "insufficient output for decoder reset bound",
739 ));
740 }
741 let output = &mut output[..output_end];
742 let written = decoder.reset(output, output_index).map_err(&mut *map_error)?;
743 assert!(written <= required, "reset wrote beyond its bound");
744 Ok(written)
745 }
746
747 /// Decodes values into an indexed output range using a streaming
748 /// [`Transcoder`].
749 ///
750 /// # Type Parameters
751 ///
752 /// - `D`: Streaming decoder accepting the source unit type.
753 /// - `M`: Mapper from decoder errors to I/O errors.
754 /// - `Value`: Decoded destination value type.
755 ///
756 /// # Parameters
757 ///
758 /// * `decoder` - Streaming decoder used for this operation.
759 /// * `map_error` - Function mapping transcode errors into I/O errors.
760 /// * `output` - Destination value storage.
761 /// * `output_index` - Start index inside `output`.
762 /// * `count` - Maximum number of values to write.
763 ///
764 /// # Returns
765 ///
766 /// The number of values written. When this method is driven through EOF
767 /// with output capacity remaining, it passes the retained tail—or an empty
768 /// input when no tail remains—to [`Transcoder::transcode_eof`] before
769 /// returning.
770 /// A short return, including zero, may mean the decoder requires a larger
771 /// contiguous output range. It does not prove conversion is complete. Use
772 /// [`Self::transcode_step`] and [`Self::transcode_eof_step`] when the stop
773 /// reason and required capacity must remain observable.
774 ///
775 /// # Errors
776 ///
777 /// Returns input errors, invalid output ranges, capacity errors from the
778 /// internal buffer, or transcode errors mapped by `map_error`.
779 /// This operation is not transactional. An error may be returned after
780 /// source units have been consumed and values have been written to
781 /// output. Progress is not rolled back, and the error does not report
782 /// the accumulated output length. Use `transcode_step` and commit each
783 /// successful progress result when previously decoded values must
784 /// remain observable after a later failure.
785 /// The method does not refill for later values once the requested output
786 /// range is full; the underlying input may still prefetch units beyond
787 /// that range during an earlier read. If EOF processing stops with
788 /// `NeedOutput`, the next batch call resumes EOF processing directly;
789 /// a short return, including zero, does not mean conversion is complete.
790 /// Use the step methods when the exact stop reason is needed. Explicitly
791 /// refilling new units, seeking, or switching to raw/single-value reads
792 /// changes the input context; callers remain responsible for the decoder
793 /// lifecycle when continuing after such a switch.
794 pub fn transcode<D, M, Value>(
795 &mut self,
796 decoder: &mut D,
797 map_error: &mut M,
798 output: &mut [Value],
799 output_index: usize,
800 count: usize,
801 ) -> Result<usize>
802 where
803 D: Transcoder<Input = I::Item, Output = Value>,
804 M: FnMut(D::Error) -> Error,
805 {
806 let output_end = SliceRange::checked_range_end(
807 output.len(),
808 output_index,
809 count,
810 "decoded output range exceeds destination buffer",
811 )?;
812 if count == 0 {
813 return Ok(0);
814 }
815 if self.eof_retry_pending {
816 return self
817 .transcode_eof_step(decoder, map_error, output, output_index, count)
818 .map(|progress| progress.written());
819 }
820 let output = &mut output[..output_end];
821 let mut written_total = 0;
822 loop {
823 if self.unread_len() == 0 && !self.fill_more()? {
824 let remaining_output = count - written_total;
825 let eof_progress = self.transcode_eof_step(
826 decoder,
827 map_error,
828 output,
829 output_index + written_total,
830 remaining_output,
831 )?;
832 written_total += eof_progress.written();
833 return Ok(written_total);
834 }
835 let units = self.unread();
836 let available_input = units.len();
837 let remaining_output = count - written_total;
838 let progress = decoder
839 .transcode(units, 0, output, output_index + written_total)
840 .map_err(&mut *map_error)?;
841 let progress = validate_decode_progress(
842 progress,
843 0,
844 available_input,
845 output_index + written_total,
846 remaining_output,
847 )?;
848 let consumed = progress.read();
849 let written = progress.written();
850 self.consume(consumed);
851 written_total += written;
852 if written_total == count {
853 return Ok(written_total);
854 }
855 match progress.status() {
856 TranscodeStatus::Complete => {}
857 TranscodeStatus::NeedOutput { .. } => {
858 return Ok(written_total);
859 }
860 TranscodeStatus::NeedInput { required, .. } => {
861 if self.fill_until(required.get())? {
862 continue;
863 }
864 let remaining_output = count - written_total;
865 let eof_progress = self.transcode_eof_step(
866 decoder,
867 map_error,
868 output,
869 output_index + written_total,
870 remaining_output,
871 )?;
872 written_total += eof_progress.written();
873 return Ok(written_total);
874 }
875 }
876 }
877 }
878
879 /// Finishes a streaming decoder into an indexed output range.
880 ///
881 /// # Type Parameters
882 ///
883 /// - `D`: Streaming decoder accepting the source unit type.
884 /// - `M`: Mapper from decoder errors to I/O errors.
885 /// - `Value`: Decoded destination value type.
886 ///
887 /// # Parameters
888 ///
889 /// * `decoder` - Streaming decoder whose final output is being collected.
890 /// * `map_error` - Function mapping transcode errors into I/O errors.
891 /// * `output` - Destination value storage.
892 /// * `output_index` - Start index inside `output`.
893 /// * `count` - Maximum number of finish values to write.
894 ///
895 /// # Returns
896 ///
897 /// The number of values written by the decoder finish operation.
898 ///
899 /// # Errors
900 ///
901 /// Returns invalid output ranges, capacity errors, or transcode
902 /// finalization errors mapped to I/O errors.
903 ///
904 /// # Panics
905 ///
906 /// Panics when the decoder reports writing more values than its
907 /// [`Transcoder::max_finish_output_len`] bound.
908 pub fn finish<D, M, Value>(
909 &self,
910 decoder: &mut D,
911 map_error: &mut M,
912 output: &mut [Value],
913 output_index: usize,
914 count: usize,
915 ) -> Result<usize>
916 where
917 D: Transcoder<Input = I::Item, Output = Value>,
918 M: FnMut(D::Error) -> Error,
919 {
920 let required = decoder
921 .max_finish_output_len()
922 .map_err(capacity_error_to_invalid_data)?;
923 // Validate the caller-supplied count range first (InvalidInput).
924 let output_end = SliceRange::checked_range_end(
925 output.len(),
926 output_index,
927 count,
928 "finish output range exceeds destination buffer",
929 )?;
930 // `count` is the caller's declared writable finish range. The
931 // destination slice may be larger, but passing extra capacity to the
932 // decoder would allow it to write beyond the range the caller granted.
933 if count < required {
934 return Err(Error::new(
935 ErrorKind::InvalidData,
936 "insufficient output for decoder finish bound",
937 ));
938 }
939 let output = &mut output[..output_end];
940 let written = decoder.finish(output, output_index).map_err(&mut *map_error)?;
941 assert!(written <= required, "finish wrote beyond its bound");
942 Ok(written)
943 }
944}
945
946impl<I> TranscodeDecodeInput<I>
947where
948 I: SeekableByteInput,
949{
950 /// Seeks the wrapped byte input and discards buffered bytes after success.
951 ///
952 /// # Parameters
953 ///
954 /// * `position` - Target seek position.
955 ///
956 /// # Returns
957 ///
958 /// The new stream position reported by the wrapped input.
959 ///
960 /// # Errors
961 ///
962 /// Returns seek errors from the wrapped input.
963 #[inline]
964 pub fn seek(&mut self, position: SeekFrom) -> Result<u64> {
965 let position = self.input.seek_to(position)?;
966 self.eof_retry_pending = false;
967 Ok(position)
968 }
969}
970
971impl<I> TranscodeDecodeInput<I>
972where
973 I: Input,
974 I::Item: Copy + Default,
975{
976 /// Reads and decodes reset, body, and finish output using caller scratch
977 /// buffers.
978 ///
979 /// This internal path keeps lifecycle allocation and error mapping in one
980 /// place for the public convenience methods.
981 ///
982 /// # Type Parameters
983 ///
984 /// - `C`: Codec accepting the wrapped input's unit type.
985 /// - `M`: Mapper from codec decode errors to I/O errors.
986 ///
987 /// # Parameters
988 ///
989 /// - `codec`: Codec whose reset, decode, and finish phases are executed.
990 /// - `reset_output`: Separate storage for reset values.
991 /// - `finish_output`: Separate storage for finish values.
992 /// - `map_error`: Mapper for codec decode errors.
993 ///
994 /// # Returns
995 ///
996 /// Returns the decoded value and initialized lengths of both output
997 /// buffers.
998 ///
999 /// # Errors
1000 ///
1001 /// Returns InvalidInput for insufficient scratch capacity, input I/O
1002 /// errors, UnexpectedEof for a truncated value, InvalidData for invalid
1003 /// codec progress, or mapped codec reset, decode, and finish errors. Each
1004 /// mapped codec-domain error owns a [`TranscodeDomainError`] identifying
1005 /// the phase; main decode errors use index `0`, the start of this input
1006 /// window. The mapper's error remains the wrapper source.
1007 ///
1008 /// # Panics
1009 ///
1010 /// Panics if reset or finish reports output beyond its declared bound.
1011 fn read_decoded_lifecycle_with_scratch_impl<C, M>(
1012 &mut self,
1013 codec: &mut C,
1014 reset_output: &mut [C::Value],
1015 finish_output: &mut [C::Value],
1016 mut map_error: M,
1017 ) -> Result<DecodeLifecycleProgress<C::Value>>
1018 where
1019 C: Codec<Unit = I::Item>,
1020 M: FnMut(C::DecodeError) -> Error,
1021 {
1022 assert_unit_bounds::<C>();
1023 if reset_output.len() < C::MAX_DECODE_RESET_VALUES {
1024 return Err(Error::new(
1025 ErrorKind::InvalidInput,
1026 "decode reset output is shorter than the codec reset bound",
1027 ));
1028 }
1029 if finish_output.len() < C::MAX_DECODE_FINISH_VALUES {
1030 return Err(Error::new(
1031 ErrorKind::InvalidInput,
1032 "decode finish output is shorter than the codec finish bound",
1033 ));
1034 }
1035 self.eof_retry_pending = false;
1036 let mut map_domain_error = |error: TranscodeDomainError<C::DecodeError>| {
1037 let contextual = error.map_source(&mut map_error);
1038 Error::new(contextual.source().kind(), contextual)
1039 };
1040 let reset_written = unsafe {
1041 // SAFETY: The reset output length check above reserves the codec's
1042 // declared decode-reset output bound.
1043 codec.decode_reset(reset_output, 0)
1044 }
1045 .map_err(|source| map_domain_error(TranscodeDomainError::reset(source)))?;
1046 assert!(
1047 reset_written <= C::MAX_DECODE_RESET_VALUES,
1048 "Codec::decode_reset wrote beyond its reset bound",
1049 );
1050
1051 let value = CodecDecodeDriver::new(&mut self.input).read_one(codec, &mut |source| {
1052 map_domain_error(TranscodeDomainError::main(source, 0))
1053 })?;
1054
1055 let finish_written = unsafe {
1056 // SAFETY: The finish output length check above reserves the
1057 // codec's declared decode-finish output bound.
1058 codec.decode_finish(finish_output, 0)
1059 }
1060 .map_err(|source| map_domain_error(TranscodeDomainError::finish(source)))?;
1061 assert!(
1062 finish_written <= C::MAX_DECODE_FINISH_VALUES,
1063 "Codec::decode_finish wrote beyond its finish bound",
1064 );
1065 Ok(DecodeLifecycleProgress::new(value, reset_written, finish_written))
1066 }
1067
1068 /// Refills the underlying buffer.
1069 ///
1070 /// # Returns
1071 ///
1072 /// Returns `true` if unread input is available after refill, or `false` at
1073 /// EOF.
1074 ///
1075 /// # Errors
1076 ///
1077 /// Propagates errors from the wrapped input while refilling.
1078 #[inline]
1079 fn fill_more(&mut self) -> Result<bool> {
1080 let result = self.input.fill_more();
1081 if matches!(result, Ok(true)) {
1082 self.eof_retry_pending = false;
1083 }
1084 result
1085 }
1086}
1087
1088impl<I> Read for TranscodeDecodeInput<I>
1089where
1090 I: ByteInput,
1091{
1092 /// Reads raw bytes through the internal buffer.
1093 ///
1094 /// # Parameters
1095 ///
1096 /// - `output`: Destination for raw buffered bytes.
1097 ///
1098 /// # Returns
1099 ///
1100 /// Returns the number of bytes read; zero indicates EOF or an empty
1101 /// destination.
1102 ///
1103 /// # Errors
1104 ///
1105 /// Propagates wrapped input or buffer errors.
1106 #[inline]
1107 fn read(&mut self, output: &mut [u8]) -> Result<usize> {
1108 // SAFETY: The full output slice is a valid destination range.
1109 unsafe { self.read_unchecked(output, 0, output.len()) }
1110 }
1111}
1112
1113impl<I> Seek for TranscodeDecodeInput<I>
1114where
1115 I: SeekableByteInput,
1116{
1117 /// Seeks the wrapped byte input and discards buffered bytes after success.
1118 ///
1119 /// # Parameters
1120 ///
1121 /// - `position`: Target byte-stream position.
1122 ///
1123 /// # Returns
1124 ///
1125 /// Returns the new byte offset after clearing buffered data.
1126 ///
1127 /// # Errors
1128 ///
1129 /// Propagates wrapped seek errors, preserving the buffer when seeking
1130 /// fails.
1131 #[inline]
1132 fn seek(&mut self, position: SeekFrom) -> Result<u64> {
1133 self.seek(position)
1134 }
1135}
1136
1137impl<I> Debug for TranscodeDecodeInput<I>
1138where
1139 I: Input,
1140 I::Item: Copy + Default,
1141 BufferedInput<I>: Debug,
1142{
1143 /// Formats this buffered decode input for debugging.
1144 ///
1145 /// # Parameters
1146 ///
1147 /// - `formatter`: Formatting sink receiving the struct and owned input.
1148 ///
1149 /// # Returns
1150 ///
1151 /// Returns success after writing the debug representation.
1152 ///
1153 /// # Errors
1154 ///
1155 /// Propagates a formatting error from the sink or wrapped input.
1156 fn fmt(&self, formatter: &mut Formatter<'_>) -> FormatResult {
1157 formatter
1158 .debug_struct("TranscodeDecodeInput")
1159 .field("input", &self.input)
1160 .finish()
1161 }
1162}