Skip to main content

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}