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