Skip to main content

qubit_codec/transcode/io/
transcode_encode_output.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 output driver that encodes values into units.
9
10use core::fmt;
11use std::collections::TryReserveError;
12use std::io::Error;
13use std::io::ErrorKind;
14use std::io::Result;
15use std::io::Seek;
16use std::io::SeekFrom;
17use std::io::Write;
18use std::result::Result as CoreResult;
19
20use qubit_io::BufferedOutput;
21use qubit_io::BufferedOutputRecovery;
22use qubit_io::ByteOutput;
23use qubit_io::Output;
24use qubit_io::SeekableByteOutput;
25use qubit_utils::SliceRange;
26use qubit_utils::allocation_error;
27
28use super::internal::capacity_error_to_invalid_data;
29use super::internal::map_encode_value_result;
30use super::transcode_progress_validation::validate_encode_progress;
31use crate::CapacityError;
32use crate::Codec;
33use crate::TranscodeEncodeErrorOf;
34use crate::TranscodeEncoder;
35use crate::TranscodeProgress;
36use crate::TranscodeStatus;
37use crate::Transcoder;
38use crate::value::codec_value_lifecycle::encode_complete_value_into_reserved;
39use crate::value::codec_value_lifecycle::max_complete_encode_units;
40
41/// Encodes an [`Output`] value stream into an [`Output`] unit stream.
42///
43/// This type owns only the unit-level [`qubit_io::BufferedOutput`]. Callers
44/// pass a [`crate::Codec`] and error mapper to each encode operation, which
45/// lets one buffered output drive different encoders without nesting buffers or
46/// storing codec-specific state in the buffer owner.
47///
48/// [`Self::flush`] only drains already buffered units. State-aware streaming
49/// encoders can use [`Self::reset`], [`Self::transcode`], and [`Self::finish`]
50/// explicitly.
51///
52/// # Type Parameters
53///
54/// * `O` - Wrapped unit output.
55///
56/// # Examples
57///
58/// ```
59/// use std::io::Cursor;
60///
61/// use qubit_codec::TranscodeEncodeOutput;
62///
63/// let output = TranscodeEncodeOutput::with_capacity(Cursor::new(Vec::<u8>::new()), 8);
64/// assert!(output.spare_capacity() >= 8);
65/// ```
66pub struct TranscodeEncodeOutput<O>
67where
68    O: Output,
69    O::Item: Copy + Default,
70{
71    /// Owns the wrapped unit sink and pending encoded units awaiting delivery.
72    output: BufferedOutput<O>,
73}
74
75impl<O> TranscodeEncodeOutput<O>
76where
77    O: Output,
78    O::Item: Copy + Default,
79{
80    /// Creates an encoder output with the default unit buffer capacity.
81    ///
82    /// # Parameters
83    ///
84    /// * `inner` - Unit output written by this adapter.
85    ///
86    /// # Returns
87    ///
88    /// A new buffered encoder output.
89    #[must_use]
90    pub fn new(inner: O) -> Self {
91        Self {
92            output: BufferedOutput::new(inner),
93        }
94    }
95
96    /// Creates an encoder output with a unit buffer of at least `capacity`.
97    ///
98    /// # Parameters
99    ///
100    /// * `inner` - Unit output written by this adapter.
101    /// * `capacity` - Requested internal unit buffer capacity.
102    ///
103    /// # Returns
104    ///
105    /// A new buffered encoder output.
106    #[must_use]
107    pub fn with_capacity(inner: O, capacity: usize) -> Self {
108        Self {
109            output: BufferedOutput::with_capacity(inner, capacity),
110        }
111    }
112
113    /// Creates an encoder output with a unit buffer of at least `capacity`.
114    ///
115    /// # Parameters
116    ///
117    /// * `inner` - Unit output written by this adapter.
118    /// * `capacity` - Requested internal unit buffer capacity.
119    ///
120    /// # Errors
121    ///
122    /// Returns an allocation error when the requested buffer cannot be
123    /// allocated.
124    ///
125    /// # Returns
126    ///
127    /// A buffered adapter owning `inner` on success.
128    pub fn try_with_capacity(inner: O, capacity: usize) -> CoreResult<Self, TryReserveError> {
129        Ok(Self {
130            output: BufferedOutput::try_with_capacity(inner, capacity)?,
131        })
132    }
133
134    /// Returns a shared reference to the wrapped unit output.
135    ///
136    /// Pending units remain in this adapter's internal buffer and are not
137    /// visible through the returned output until [`Self::flush`] succeeds.
138    ///
139    /// # Returns
140    ///
141    /// A shared reference to the wrapped unit output.
142    #[must_use]
143    #[inline]
144    pub const fn inner(&self) -> &O {
145        self.output.inner()
146    }
147
148    /// Returns the available capacity of the spare output buffer.
149    ///
150    /// # Returns
151    ///
152    /// The number of output units that can still be appended without flushing.
153    #[must_use]
154    #[inline]
155    pub fn spare_capacity(&self) -> usize {
156        self.output.spare_capacity()
157    }
158
159    /// Returns raw spare-buffer parts for the internal output buffer.
160    ///
161    /// # Returns
162    ///
163    /// The full backing storage, the spare start index, and the spare unit
164    /// count.
165    #[must_use]
166    #[inline]
167    pub fn spare_raw_parts_mut(&mut self) -> (&mut [O::Item], usize, usize) {
168        self.output.spare_raw_parts_mut()
169    }
170
171    /// Marks `count` units from [`Self::spare_raw_parts_mut`] as written.
172    ///
173    /// # Parameters
174    ///
175    /// * `count` - Initialized units to commit from the spare window.
176    ///
177    /// # Safety
178    ///
179    /// The caller must guarantee that `count <= Self::spare_capacity()` and
180    /// that the corresponding units in the returned spare slice have been
181    /// initialized.
182    #[inline]
183    pub unsafe fn advance(&mut self, count: usize) {
184        // SAFETY: The caller guarantees `count` and initialization invariants.
185        unsafe { self.output.advance(count) }
186    }
187
188    /// Ensures that at least `count` spare units are available.
189    ///
190    /// # Parameters
191    ///
192    /// * `count` - Number of spare units required.
193    ///
194    /// # Errors
195    ///
196    /// Returns allocation errors mapped to [`ErrorKind::OutOfMemory`], or I/O
197    /// errors from the wrapped output while delivering pending units.
198    pub fn ensure_spare_capacity(&mut self, count: usize) -> Result<()> {
199        self.output.try_reserve_capacity(count).map_err(allocation_error)?;
200        self.output.ensure_spare_capacity(count)
201    }
202
203    /// Consumes this adapter without flushing the wrapped output.
204    ///
205    /// This method does not call [`Self::flush`] and performs no I/O. `Pending`
206    /// units were not reported as written and may be retried. `Indeterminate`
207    /// means an inner write panicked and may have produced an external prefix;
208    /// do not replay it automatically.
209    ///
210    /// # Returns
211    ///
212    /// The wrapped output and pending or indeterminate units.
213    #[must_use = "the returned output and recovery status must be handled"]
214    #[inline]
215    pub fn into_parts(self) -> (O, BufferedOutputRecovery<O::Item>) {
216        self.output.into_parts()
217    }
218
219    /// Flushes buffered units without finishing any encoder stream.
220    ///
221    /// # Errors
222    ///
223    /// Returns errors from the wrapped output while flushing pending units.
224    pub fn flush(&mut self) -> Result<()> {
225        self.output.flush()
226    }
227
228    /// Encodes one codec value into this buffered unit output.
229    ///
230    /// The method grows the persistent internal buffer when necessary, then
231    /// writes the complete encoded value into its spare window.
232    ///
233    /// # Type Parameters
234    ///
235    /// * `C` - Codec producing the wrapped output unit type.
236    /// * `M` - Mapper from codec errors into I/O errors.
237    ///
238    /// # Parameters
239    ///
240    /// * `codec` - Codec used for this single-value encode.
241    /// * `value` - Value to encode.
242    /// * `map_error` - Mapper for codec-domain encode errors.
243    ///
244    /// # Errors
245    ///
246    /// Returns I/O errors from the wrapped output, `InvalidInput` when the
247    /// codec output bound overflows or the value is outside the codec domain,
248    /// or the error returned by `map_error` for codec encode, reset, and finish
249    /// failures.
250    ///
251    /// # Panics
252    ///
253    /// Panics when the codec violates its declared reset, value-width, or
254    /// finish bounds, or when `encode` writes a length different from
255    /// `encode_len` in the same reset state.
256    pub fn write_encoded_with<C, M>(&mut self, codec: &mut C, value: &C::Value, mut map_error: M) -> Result<()>
257    where
258        C: Codec<Unit = O::Item>,
259        M: FnMut(C::EncodeError) -> Error,
260    {
261        let max_units = map_encode_value_result(
262            max_complete_encode_units::<C>().map_err(TranscodeEncodeErrorOf::<C>::from),
263            &mut map_error,
264        )?;
265        self.ensure_spare_capacity(max_units)?;
266        let (units, output_index, available) = self.output.spare_raw_parts_mut();
267        debug_assert!(
268            available >= max_units,
269            "reserved spare buffer is smaller than codec upper bound",
270        );
271        let written = map_encode_value_result(
272            encode_complete_value_into_reserved(codec, value, units, output_index, max_units),
273            &mut map_error,
274        )?;
275        // SAFETY: The spare buffer has the conservative complete lifecycle
276        // capacity, and the helper reports how many initialized units it
277        // actually wrote.
278        unsafe {
279            self.output.advance(written);
280        }
281        Ok(())
282    }
283
284    /// Runs encoder reset and buffers any stream-prefix units.
285    ///
286    /// This method reserves enough persistent buffer capacity for all reset
287    /// output before calling `encoder`. Preparing that space may deliver
288    /// previously buffered units to the wrapped output and can return an I/O
289    /// error before `encoder.reset` runs. This delivery does not call the
290    /// wrapped output's `flush` method.
291    ///
292    /// # Type Parameters
293    ///
294    /// * `E` - Transcoder producing the wrapped output unit type.
295    /// * `M` - Mapper from transcoder errors into I/O errors.
296    /// * `Value` - Source value type accepted by the transcoder.
297    ///
298    /// # Parameters
299    ///
300    /// * `encoder` - Transcoder whose stream prefix is being collected.
301    /// * `map_error` - Mapper for reset failures.
302    ///
303    /// # Errors
304    ///
305    /// Returns capacity errors, allocation errors, or reset errors mapped by
306    /// `map_error`.
307    ///
308    /// # Panics
309    ///
310    /// Panics when `encoder` writes more than its declared reset bound.
311    pub fn reset<E, M, Value>(&mut self, encoder: &mut E, map_error: &mut M) -> Result<()>
312    where
313        E: Transcoder<Input = Value, Output = O::Item>,
314        M: FnMut(E::Error) -> Error,
315    {
316        let required = encoder.max_reset_output_len().map_err(capacity_error_to_invalid_data)?;
317        self.ensure_spare_capacity(required)?;
318        let (units, output_index, available) = self.output.spare_raw_parts_mut();
319        debug_assert!(
320            available >= required,
321            "insufficient reset capacity reserved in spare output buffer",
322        );
323        let written = encoder.reset(units, output_index).map_err(&mut *map_error)?;
324        assert!(written <= required, "reset wrote beyond its bound");
325        // SAFETY: The encoder reported initialized units within the spare
326        // range reserved above.
327        unsafe {
328            self.output.advance(written);
329        }
330        Ok(())
331    }
332
333    /// Encodes at most one step of the selected input range.
334    ///
335    /// Unlike [`Self::transcode`], this method does not reserve output space
336    /// for the entire range and calls the encoder exactly once. The returned
337    /// progress is relative to this call's input and output windows. Advance
338    /// the input index by [`TranscodeProgress::read`]; if the status is
339    /// `NeedOutput`, provide the requested spare capacity before retrying.
340    /// Written units have already been committed to this adapter's pending
341    /// buffer and must not be advanced again. A zero count validates the range
342    /// and returns complete progress without delivering pending units or
343    /// calling the encoder.
344    ///
345    /// # Parameters
346    ///
347    /// * `encoder` - Encoder that processes one progress step.
348    /// * `map_error` - Maps encoder errors to I/O errors.
349    /// * `input` - Source values.
350    /// * `input_index` - Start index inside `input`.
351    /// * `count` - Number of values available from `input_index`.
352    ///
353    /// # Returns
354    ///
355    /// Progress for the single encoder call, including consumed input,
356    /// committed output, and whether more output capacity is needed.
357    ///
358    /// # Errors
359    ///
360    /// Returns invalid input ranges, capacity, encoder, or output errors. An
361    /// invalid encoder progress report is returned as `ErrorKind::InvalidData`.
362    /// An error does not provide general transactional rollback or complete
363    /// progress. The encoder may already have advanced, but units written by
364    /// its failing call are not committed to this adapter's pending output.
365    /// Do not replay the original input range without an encoder-specific
366    /// recovery protocol. Earlier pending units retain the wrapped output's
367    /// recovery contract; reset starts a new logical stream and does not undo
368    /// output already delivered.
369    ///
370    /// # Examples
371    ///
372    /// ```
373    /// use std::io::Cursor;
374    ///
375    /// # use core::convert::Infallible;
376    /// # use core::num::NonZeroUsize;
377    /// # use qubit_codec::Codec;
378    /// # use qubit_codec::CodecTranscodeEncoder;
379    /// # use qubit_codec::DecodeFailure;
380    /// use qubit_codec::TranscodeEncodeOutput;
381    /// use qubit_codec::TranscodeEncoder;
382    /// use qubit_codec::TranscodeStatus;
383    ///
384    /// # struct ByteCodec;
385    /// # impl Codec for ByteCodec {
386    /// #     type Value = u8;
387    /// #     type Unit = u8;
388    /// #     type DecodeError = Infallible;
389    /// #     type EncodeError = Infallible;
390    /// #     const MIN_UNITS_PER_VALUE: usize = 1;
391    /// #     const MAX_ENCODE_UNITS_PER_VALUE: usize = 1;
392    /// #     const MAX_DECODE_UNITS_PER_VALUE: usize = 1;
393    /// #     unsafe fn decode(
394    /// #         &mut self,
395    /// #         input: &[u8],
396    /// #         index: usize,
397    /// #     ) -> Result<(u8, NonZeroUsize), DecodeFailure<Infallible>> {
398    /// #         Ok((input[index], NonZeroUsize::MIN))
399    /// #     }
400    /// #     unsafe fn encode(
401    /// #         &mut self,
402    /// #         value: &u8,
403    /// #         output: &mut [u8],
404    /// #         index: usize,
405    /// #     ) -> Result<usize, Infallible> {
406    /// #         output[index] = *value;
407    /// #         Ok(1)
408    /// #     }
409    /// # }
410    /// fn encode<E>(encoder: &mut E, values: &[E::Input]) -> std::io::Result<Vec<u8>>
411    /// where
412    ///     E: TranscodeEncoder<Output = u8>,
413    /// {
414    ///     let mut output = TranscodeEncodeOutput::with_capacity(Cursor::new(Vec::new()), 8);
415    ///     let mut map_error = |_| std::io::Error::other("encode error");
416    ///     output.reset(encoder, &mut map_error)?;
417    ///     let mut offset = 0;
418    ///     while offset < values.len() {
419    ///         let progress = output.transcode_step(
420    ///             encoder,
421    ///             &mut map_error,
422    ///             values,
423    ///             offset,
424    ///             values.len() - offset,
425    ///         )?;
426    ///         offset += progress.read();
427    ///         if let TranscodeStatus::NeedOutput { required, .. } = progress.status() {
428    ///             output.ensure_spare_capacity(required.get())?;
429    ///         }
430    ///     }
431    ///     output.finish(encoder, &mut map_error)?;
432    ///     let (cursor, _) = output.into_parts();
433    ///     Ok(cursor.into_inner())
434    /// }
435    ///
436    /// let mut encoder = CodecTranscodeEncoder::new(ByteCodec);
437    /// assert_eq!(encode(&mut encoder, &[1, 2, 3]).unwrap(), vec![1, 2, 3]);
438    /// let mut empty_encoder = CodecTranscodeEncoder::new(ByteCodec);
439    /// assert_eq!(encode(&mut empty_encoder, &[]).unwrap(), Vec::<u8>::new());
440    /// ```
441    pub fn transcode_step<E, M, Value>(
442        &mut self,
443        encoder: &mut E,
444        map_error: &mut M,
445        input: &[Value],
446        input_index: usize,
447        count: usize,
448    ) -> Result<TranscodeProgress>
449    where
450        E: TranscodeEncoder<Input = Value, Output = O::Item>,
451        M: FnMut(E::Error) -> Error,
452    {
453        let input_end = SliceRange::checked_range_end(
454            input.len(),
455            input_index,
456            count,
457            "encode input range exceeds source buffer",
458        )?;
459        if count == 0 {
460            return Ok(TranscodeProgress::complete(0, 0));
461        }
462        let required = encoder
463            .max_transcode_output_len(1)
464            .map_err(capacity_error_to_invalid_data)?
465            .max(1);
466        self.ensure_spare_capacity(required)?;
467        let (units, output_index, available_output) = self.output.spare_raw_parts_mut();
468        let progress = encoder
469            .transcode(&input[..input_end], input_index, units, output_index)
470            .map_err(&mut *map_error)?;
471        let progress = validate_encode_progress(progress, input_index, count, output_index, available_output)?;
472        // SAFETY: Validated progress fits the spare output window.
473        unsafe {
474            self.output.advance(progress.written());
475        }
476        Ok(progress)
477    }
478
479    /// Encodes values from an indexed input range using a streaming
480    /// [`Transcoder`].
481    ///
482    /// This streaming path reserves the encoder's conservative output bound
483    /// for the whole batch before calling it. Preparing that space may deliver
484    /// previously buffered units to the wrapped output and can return an I/O
485    /// error before consuming source values. Split large batches into smaller
486    /// calls when you need to limit the memory required for one operation.
487    ///
488    /// # Type Parameters
489    ///
490    /// * `E` - Encoder producing the wrapped output unit type.
491    /// * `M` - Mapper from encoder errors into I/O errors.
492    /// * `Value` - Source value type accepted by the encoder.
493    ///
494    /// # Parameters
495    ///
496    /// * `encoder` - Streaming encoder used for this operation.
497    /// * `map_error` - Function mapping transcode errors into I/O errors.
498    /// * `input` - Source values.
499    /// * `input_index` - Start index inside `input`.
500    /// * `count` - Maximum number of values to encode.
501    ///
502    /// # Returns
503    ///
504    /// The number of source values consumed.
505    ///
506    /// # Errors
507    ///
508    /// Returns invalid input ranges, capacity, transcode, or output errors. An
509    /// output-bound contract violation is reported as `ErrorKind::InvalidData`.
510    /// An error does not provide general transactional rollback or complete
511    /// progress. The encoder may already have advanced, while units written by
512    /// its failing call are not committed to this adapter's pending output.
513    /// Do not replay the original input range unless the concrete encoder
514    /// provides an explicit recovery protocol. Previously committed pending
515    /// output remains subject to the wrapped output's recovery contract, and
516    /// reset starts a new logical stream without undoing output already
517    /// delivered.
518    ///
519    /// # Examples
520    ///
521    /// A value that only implements [`Transcoder`] is not an encoder and cannot
522    /// be passed to this method.
523    ///
524    /// ```compile_fail
525    /// use std::io::Error;
526    /// use std::io::sink;
527    ///
528    /// use qubit_codec::CapacityError;
529    /// use qubit_codec::TranscodeEncodeError;
530    /// use qubit_codec::TranscodeEncodeOutput;
531    /// use qubit_codec::TranscodeProgress;
532    /// use qubit_codec::Transcoder;
533    ///
534    /// struct GenericTranscoder;
535    ///
536    /// impl Transcoder for GenericTranscoder {
537    ///     type Input = u8;
538    ///     type Output = u8;
539    ///     type Error = TranscodeEncodeError<(), u8>;
540    ///
541    ///     fn max_transcode_output_len(
542    ///         &self,
543    ///         input_len: usize,
544    ///     ) -> Result<usize, CapacityError> {
545    ///         Ok(input_len)
546    ///     }
547    ///
548    ///     fn reset(
549    ///         &mut self,
550    ///         _output: &mut [u8],
551    ///         _output_index: usize,
552    ///     ) -> Result<usize, Self::Error> {
553    ///         Ok(0)
554    ///     }
555    ///
556    ///     fn transcode(
557    ///         &mut self,
558    ///         input: &[u8],
559    ///         input_index: usize,
560    ///         _output: &mut [u8],
561    ///         _output_index: usize,
562    ///     ) -> Result<TranscodeProgress, Self::Error> {
563    ///         Ok(TranscodeProgress::complete(input.len() - input_index, 0))
564    ///     }
565    ///
566    ///     fn finish(
567    ///         &mut self,
568    ///         _output: &mut [u8],
569    ///         _output_index: usize,
570    ///     ) -> Result<usize, Self::Error> {
571    ///         Ok(0)
572    ///     }
573    /// }
574    ///
575    /// let mut output = TranscodeEncodeOutput::with_capacity(sink(), 1);
576    /// let mut transcoder = GenericTranscoder;
577    /// let mut map_error = |_| Error::other("transcode error");
578    /// let _ = output.transcode(
579    ///     &mut transcoder,
580    ///     &mut map_error,
581    ///     &[0_u8],
582    ///     0,
583    ///     1,
584    /// );
585    /// ```
586    pub fn transcode<E, M, Value>(
587        &mut self,
588        encoder: &mut E,
589        map_error: &mut M,
590        input: &[Value],
591        input_index: usize,
592        count: usize,
593    ) -> Result<usize>
594    where
595        E: TranscodeEncoder<Input = Value, Output = O::Item>,
596        M: FnMut(E::Error) -> Error,
597    {
598        let input_end = SliceRange::checked_range_end(
599            input.len(),
600            input_index,
601            count,
602            "encode input range exceeds source buffer",
603        )?;
604        if count == 0 {
605            return Ok(0);
606        }
607        let required = encoder
608            .max_transcode_output_len(count)
609            .map_err(capacity_error_to_invalid_data)?
610            .max(1);
611        self.ensure_spare_capacity(required)?;
612        let input = &input[..input_end];
613        let mut read_total = 0;
614        while read_total < count {
615            let (units, output_index, available_output) = self.output.spare_raw_parts_mut();
616            let remaining_input = count - read_total;
617            let progress = encoder
618                .transcode(input, input_index + read_total, units, output_index)
619                .map_err(&mut *map_error)?;
620            let progress = validate_encode_progress(
621                progress,
622                input_index + read_total,
623                remaining_input,
624                output_index,
625                available_output,
626            )?;
627            let read = progress.read();
628            let written = progress.written();
629            // SAFETY: The progress bounds check above proved that the encoder
630            // initialized no more than the available spare output window.
631            unsafe {
632                self.output.advance(written);
633            }
634            read_total += read;
635            if progress.is_complete() {
636                return Ok(read_total);
637            }
638            if let TranscodeStatus::NeedOutput { required, .. } = progress.status()
639                && (read_total == count || available_output - written < required.get() || (read == 0 && written == 0))
640            {
641                return Err(Error::new(
642                    ErrorKind::InvalidData,
643                    "encoder output bound was insufficient",
644                ));
645            }
646        }
647        Ok(read_total)
648    }
649
650    /// Finishes the encoder and flushes the wrapped unit output.
651    ///
652    /// This method writes final units directly into the internal spare buffer,
653    /// growing it when [`Transcoder::max_finish_output_len`] exceeds the
654    /// current capacity.
655    ///
656    /// # Type Parameters
657    ///
658    /// * `E` - Transcoder producing the wrapped output unit type.
659    /// * `M` - Mapper from transcoder errors into I/O errors.
660    /// * `Value` - Source value type accepted by the transcoder.
661    ///
662    /// # Parameters
663    ///
664    /// * `encoder` - Encoder whose final units are being collected.
665    /// * `map_error` - Function mapping transcode errors into I/O errors.
666    ///
667    /// # Errors
668    ///
669    /// Returns capacity, transcode finalization, or wrapped output flush
670    /// errors.
671    ///
672    /// # Panics
673    ///
674    /// Panics when the encoder exceeds its declared finish-output bound.
675    pub fn finish<E, M, Value>(&mut self, encoder: &mut E, map_error: &mut M) -> Result<()>
676    where
677        E: Transcoder<Input = Value, Output = O::Item>,
678        M: FnMut(E::Error) -> Error,
679    {
680        self.finish_to_buffer(encoder, map_error)?;
681        self.output.flush()
682    }
683
684    /// Finishes the encoder while retaining final units in the output buffer.
685    ///
686    /// This method separates encoder finalization from output delivery. It is
687    /// useful when a caller must record successful finalization before a later
688    /// flush can fail. Call [`Self::flush`] to deliver the retained units.
689    ///
690    /// # Type Parameters
691    ///
692    /// * `E` - Transcoder producing the wrapped output unit type.
693    /// * `M` - Mapper from transcoder errors into I/O errors.
694    /// * `Value` - Source value type accepted by the transcoder.
695    ///
696    /// # Parameters
697    ///
698    /// * `encoder` - Encoder whose final units are being collected.
699    /// * `map_error` - Function mapping transcode errors into I/O errors.
700    ///
701    /// # Errors
702    ///
703    /// Returns capacity planning, allocation, or transcoder finalization
704    /// errors. It does not perform output I/O; use [`Self::finish`] to deliver
705    /// the buffered final units and flush the wrapped output.
706    ///
707    /// # Panics
708    ///
709    /// Panics when `encoder` writes more units than its declared finish bound.
710    pub fn finish_to_buffer<E, M, Value>(&mut self, encoder: &mut E, map_error: &mut M) -> Result<()>
711    where
712        E: Transcoder<Input = Value, Output = O::Item>,
713        M: FnMut(E::Error) -> Error,
714    {
715        let required = match encoder.max_finish_output_len() {
716            Ok(required) => required,
717            Err(error) => return Err(capacity_error_to_invalid_data(error)),
718        };
719        let pending = self.output.capacity() - self.output.spare_capacity();
720        let capacity = pending
721            .checked_add(required)
722            .ok_or_else(|| capacity_error_to_invalid_data(CapacityError::OutputLengthOverflow))?;
723        self.output.try_reserve_capacity(capacity).map_err(allocation_error)?;
724        let (units, output_index, available) = self.output.spare_raw_parts_mut();
725        debug_assert!(
726            available >= required,
727            "insufficient finish capacity reserved in spare output buffer",
728        );
729        let written = encoder.finish(units, output_index).map_err(&mut *map_error)?;
730        assert!(written <= required, "finish wrote beyond its bound");
731        // SAFETY: The encoder reported initialized units within the spare
732        // range that was reserved above.
733        unsafe {
734            self.output.advance(written);
735        }
736        Ok(())
737    }
738}
739
740impl<O> TranscodeEncodeOutput<O>
741where
742    O: SeekableByteOutput,
743{
744    /// Flushes pending bytes, then seeks the wrapped byte output.
745    ///
746    /// # Parameters
747    ///
748    /// * `position` - Target seek position.
749    ///
750    /// # Returns
751    ///
752    /// The new stream position reported by the wrapped output.
753    ///
754    /// # Errors
755    ///
756    /// Returns flush or seek errors from the wrapped output.
757    pub fn seek(&mut self, position: SeekFrom) -> Result<u64> {
758        self.output.seek_to(position)
759    }
760}
761
762impl<O> Write for TranscodeEncodeOutput<O>
763where
764    O: ByteOutput,
765{
766    /// Writes raw bytes through the internal buffer without encoding them.
767    ///
768    /// # Parameters
769    ///
770    /// * `input` - Bytes to append to the buffered unit output.
771    ///
772    /// # Returns
773    ///
774    /// The number of bytes accepted, which may be shorter than `input`.
775    ///
776    /// # Errors
777    ///
778    /// Propagates wrapped-output errors when buffer delivery is needed.
779    #[inline]
780    fn write(&mut self, input: &[u8]) -> Result<usize> {
781        Output::write(&mut self.output, input)
782    }
783
784    /// Writes all raw bytes through the internal buffer without encoding them.
785    ///
786    /// # Parameters
787    ///
788    /// * `input` - Bytes that must all be accepted before success.
789    ///
790    /// # Errors
791    ///
792    /// Propagates output errors and returns `WriteZero` if output stops
793    /// progressing.
794    ///
795    /// # Panics
796    ///
797    /// Panics when the wrapped output reports more bytes than supplied.
798    fn write_all(&mut self, input: &[u8]) -> Result<()> {
799        let mut written = 0;
800        while written < input.len() {
801            let count = match Output::write(&mut self.output, &input[written..]) {
802                Ok(count) => count,
803                Err(error) if error.kind() == ErrorKind::Interrupted => continue,
804                Err(error) => return Err(error),
805            };
806            if count == 0 {
807                return Err(Error::from(ErrorKind::WriteZero));
808            }
809            assert!(
810                count <= input.len() - written,
811                "Output::write returned a count beyond the input length",
812            );
813            written += count;
814        }
815        Ok(())
816    }
817
818    /// Flushes buffered bytes to the wrapped output without finishing an
819    /// encoder.
820    ///
821    /// # Errors
822    ///
823    /// Propagates wrapped-output flush errors.
824    #[inline]
825    fn flush(&mut self) -> Result<()> {
826        TranscodeEncodeOutput::flush(self)
827    }
828}
829
830impl<O> Seek for TranscodeEncodeOutput<O>
831where
832    O: SeekableByteOutput,
833{
834    /// Flushes pending bytes, then seeks the wrapped byte output.
835    ///
836    /// # Parameters
837    ///
838    /// * `position` - Target position relative to the selected seek origin.
839    ///
840    /// # Returns
841    ///
842    /// The new absolute byte position.
843    ///
844    /// # Errors
845    ///
846    /// Propagates flush or seek errors from the wrapped output.
847    #[inline]
848    fn seek(&mut self, position: SeekFrom) -> Result<u64> {
849        self.seek(position)
850    }
851}
852
853impl<O> fmt::Debug for TranscodeEncodeOutput<O>
854where
855    O: Output,
856    O::Item: Copy + Default,
857    BufferedOutput<O>: fmt::Debug,
858{
859    /// Formats the owned buffer and underlying output for diagnostics.
860    ///
861    /// # Parameters
862    ///
863    /// * `formatter` - Destination and formatting options.
864    ///
865    /// # Errors
866    ///
867    /// Returns a formatting error if the destination rejects output.
868    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
869        formatter
870            .debug_struct("TranscodeEncodeOutput")
871            .field("output", &self.output)
872            .finish()
873    }
874}