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