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