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