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