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