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::{
11    fmt,
12    num::NonZeroUsize,
13};
14use std::collections::TryReserveError;
15use std::io::{
16    Error,
17    ErrorKind,
18    Result,
19    Seek,
20    SeekFrom,
21    Write,
22};
23
24use qubit_io::{
25    Buffer,
26    BufferedOutput,
27    Output,
28    Seekable,
29    UncheckedSlice,
30};
31
32use crate::{
33    CapacityError,
34    Codec,
35    TranscodeEncodeError,
36    TranscodeEncodeErrorOf,
37    TranscodeEncoder,
38    TranscodeStatus,
39    Transcoder,
40    value::codec_value_lifecycle::{
41        encode_complete_value_into_reserved,
42        max_complete_encode_units,
43    },
44};
45
46use super::transcode_progress_validation::validate_encode_progress;
47
48/// Encodes an [`Output`] value stream into an [`Output`] unit stream.
49///
50/// This type owns only the unit-level [`qubit_io::BufferedOutput`]. Callers
51/// pass a [`crate::Codec`] and error mapper to each encode operation, which
52/// lets one buffered output drive different encoders without nesting buffers or
53/// storing codec-specific state in the buffer owner.
54///
55/// [`Self::flush`] only drains already buffered units. State-aware streaming
56/// encoders can use [`Self::reset`], [`Self::transcode`], and [`Self::finish`]
57/// explicitly.
58///
59/// # Type Parameters
60///
61/// * `O` - Wrapped unit output.
62pub struct TranscodeEncodeOutput<O>
63where
64    O: Output,
65    O::Item: Copy + Default,
66{
67    output: BufferedOutput<O>,
68}
69
70impl<O> TranscodeEncodeOutput<O>
71where
72    O: Output,
73    O::Item: Copy + Default,
74{
75    /// Creates an encoder output with the default unit buffer capacity.
76    ///
77    /// # Parameters
78    ///
79    /// * `inner` - Unit output written by this adapter.
80    ///
81    /// # Returns
82    ///
83    /// A new buffered encoder output.
84    #[must_use]
85    pub fn new(inner: O) -> Self {
86        Self {
87            output: BufferedOutput::new(inner),
88        }
89    }
90
91    /// Creates an encoder output with a unit buffer of at least `capacity`.
92    ///
93    /// # Parameters
94    ///
95    /// * `inner` - Unit output written by this adapter.
96    /// * `capacity` - Requested internal unit buffer capacity.
97    ///
98    /// # Returns
99    ///
100    /// A new buffered encoder output.
101    #[must_use]
102    pub fn with_capacity(inner: O, capacity: usize) -> Self {
103        Self {
104            output: BufferedOutput::with_capacity(inner, capacity),
105        }
106    }
107
108    /// Creates an encoder output with a unit buffer of at least `capacity`.
109    ///
110    /// # Parameters
111    ///
112    /// * `inner` - Unit output written by this adapter.
113    /// * `capacity` - Requested internal unit buffer capacity.
114    ///
115    /// # Errors
116    ///
117    /// Returns an allocation error when the requested buffer cannot be
118    /// allocated.
119    #[inline]
120    pub fn try_with_capacity(
121        inner: O,
122        capacity: usize,
123    ) -> std::result::Result<Self, TryReserveError> {
124        Ok(Self {
125            output: BufferedOutput::try_with_capacity(inner, capacity)?,
126        })
127    }
128
129    /// Returns a shared reference to the wrapped unit output.
130    ///
131    /// Pending units remain in this adapter's internal buffer and are not
132    /// visible through the returned output until [`Self::flush`] succeeds.
133    ///
134    /// # Returns
135    ///
136    /// A shared reference to the wrapped unit output.
137    #[must_use]
138    pub const fn inner(&self) -> &O {
139        self.output.inner()
140    }
141
142    /// Returns the available capacity of the spare output buffer.
143    ///
144    /// # Returns
145    ///
146    /// The number of output units that can still be appended without flushing.
147    #[must_use]
148    pub fn spare_capacity(&self) -> usize {
149        self.output.spare_capacity()
150    }
151
152    /// Returns raw spare-buffer parts for the internal output buffer.
153    ///
154    /// # Returns
155    ///
156    /// The full backing storage, the spare start index, and the spare unit
157    /// count.
158    #[must_use]
159    pub fn spare_raw_parts_mut(&mut self) -> (&mut [O::Item], usize, usize) {
160        self.output.spare_raw_parts_mut()
161    }
162
163    /// Marks `count` units from [`Self::spare_raw_parts_mut`] as written.
164    ///
165    /// # Safety
166    ///
167    /// The caller must guarantee that `count <= Self::spare_capacity()` and
168    /// that the corresponding units in the returned spare slice have been
169    /// initialized.
170    pub unsafe fn advance(&mut self, count: usize) {
171        // SAFETY: The caller guarantees `count` and initialization invariants.
172        unsafe { self.output.advance(count) }
173    }
174
175    /// Ensures that at least `count` spare units are available.
176    ///
177    /// # Parameters
178    ///
179    /// * `count` - Number of spare units required.
180    ///
181    /// # Errors
182    ///
183    /// Returns allocation errors mapped to [`ErrorKind::OutOfMemory`], or I/O
184    /// errors from the wrapped output while flushing pending units.
185    pub fn ensure_spare_capacity(&mut self, count: usize) -> Result<()> {
186        let pending = self.output.capacity() - self.output.spare_capacity();
187        let required_capacity = pending.saturating_add(count);
188        self.output
189            .try_reserve_capacity(required_capacity)
190            .map_err(allocation_to_io_error)?;
191        self.output.ensure_spare_capacity(count)
192    }
193
194    fn ensure_transcode_spare_capacity(
195        &mut self,
196        required: NonZeroUsize,
197    ) -> Result<()> {
198        self.ensure_spare_capacity(required.get())
199    }
200
201    /// Consumes this adapter without flushing the wrapped output.
202    ///
203    /// This method does not call [`Self::flush`] and performs no I/O. Pending
204    /// units remain in the returned buffer, which transfers their delivery
205    /// responsibility to the caller.
206    ///
207    /// # Returns
208    ///
209    /// The wrapped output and the buffer holding pending units.
210    #[must_use = "the returned output and pending buffer must be handled"]
211    pub fn into_parts(self) -> (O, Buffer<O::Item>) {
212        self.output.into_parts()
213    }
214
215    /// Flushes buffered units without finishing any encoder stream.
216    ///
217    /// # Errors
218    ///
219    /// Returns errors from the wrapped output while flushing pending units.
220    pub fn flush(&mut self) -> Result<()> {
221        self.output.flush()
222    }
223
224    /// Encodes one codec value into this buffered unit output.
225    ///
226    /// The method grows the persistent internal buffer when necessary, then
227    /// writes the complete encoded value into its spare window.
228    ///
229    /// # Parameters
230    ///
231    /// * `codec` - Codec used for this single-value encode.
232    /// * `value` - Value to encode.
233    /// * `map_error` - Mapper for codec-domain encode errors.
234    ///
235    /// # Errors
236    ///
237    /// Returns I/O errors from the wrapped output, `InvalidInput` when the
238    /// codec output bound overflows or the value is outside the codec domain,
239    /// or the error returned by `map_error` for codec encode, reset, and finish
240    /// failures.
241    ///
242    /// # Panics
243    ///
244    /// Panics when the codec violates its declared reset, value-width, or
245    /// finish bounds, or when `encode` writes a length different from
246    /// `encode_len` in the same reset state.
247    pub fn write_encoded_with<C, M>(
248        &mut self,
249        codec: &mut C,
250        value: &C::Value,
251        mut map_error: M,
252    ) -> Result<()>
253    where
254        C: Codec<Unit = O::Item>,
255        M: FnMut(C::EncodeError) -> Error,
256    {
257        let max_units = map_encode_value_result(
258            max_complete_encode_units::<C>()
259                .map_err(TranscodeEncodeErrorOf::<C>::from),
260            &mut map_error,
261        )?;
262        self.ensure_spare_capacity(max_units)?;
263        let (units, output_index, available) =
264            self.output.spare_raw_parts_mut();
265        debug_assert!(
266            available >= max_units,
267            "reserved spare buffer is smaller than codec upper bound",
268        );
269        let written = map_encode_value_result(
270            encode_complete_value_into_reserved(
271                codec,
272                value,
273                units,
274                output_index,
275                max_units,
276            ),
277            &mut map_error,
278        )?;
279        // SAFETY: The spare buffer has the conservative complete lifecycle
280        // capacity, and the helper reports how many initialized units it
281        // actually wrote.
282        unsafe {
283            self.output.advance(written);
284        }
285        Ok(())
286    }
287
288    /// Runs encoder reset and buffers any stream-prefix units.
289    ///
290    /// This method reserves enough persistent buffer capacity for all reset
291    /// output before calling `encoder`. It does not flush pending units.
292    ///
293    /// # Errors
294    ///
295    /// Returns capacity errors, allocation errors, or reset errors mapped by
296    /// `map_error`.
297    ///
298    /// # Panics
299    ///
300    /// Panics when `encoder` writes more than its declared reset bound.
301    pub fn reset<E, M, Value>(
302        &mut self,
303        encoder: &mut E,
304        map_error: &mut M,
305    ) -> Result<()>
306    where
307        E: Transcoder<Input = Value, Output = O::Item>,
308        M: FnMut(E::Error) -> Error,
309    {
310        let required = encoder
311            .max_reset_output_len()
312            .map_err(capacity_error_to_invalid_data)?;
313        self.ensure_spare_capacity(required)?;
314        let (units, output_index, available) =
315            self.output.spare_raw_parts_mut();
316        debug_assert!(
317            available >= required,
318            "insufficient reset capacity reserved in spare output buffer",
319        );
320        let written = encoder
321            .reset(units, output_index)
322            .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 values from an indexed input range using a streaming
333    /// [`Transcoder`].
334    ///
335    /// This streaming path writes directly into the internal spare buffer and
336    /// grows it for any larger `NeedOutput.required` value reported by
337    /// `encoder`.
338    ///
339    /// # Parameters
340    ///
341    /// * `encoder` - Streaming encoder used for this operation.
342    /// * `map_error` - Function mapping transcode errors into I/O errors.
343    /// * `input` - Source values.
344    /// * `input_index` - Start index inside `input`.
345    /// * `count` - Maximum number of values to encode.
346    ///
347    /// # Returns
348    ///
349    /// The number of source values consumed.
350    ///
351    /// # Errors
352    ///
353    /// Returns invalid input ranges, capacity, transcode, or output errors.
354    ///
355    /// # Examples
356    ///
357    /// A value that only implements [`Transcoder`] is not an encoder and cannot
358    /// be passed to this method.
359    ///
360    /// ```compile_fail
361    /// use qubit_codec::{
362    ///     CapacityError, TranscodeEncodeError, TranscodeEncodeOutput,
363    ///     TranscodeProgress, Transcoder,
364    /// };
365    ///
366    /// struct GenericTranscoder;
367    ///
368    /// impl Transcoder for GenericTranscoder {
369    ///     type Input = u8;
370    ///     type Output = u8;
371    ///     type Error = TranscodeEncodeError<(), u8>;
372    ///
373    ///     fn max_transcode_output_len(
374    ///         &self,
375    ///         input_len: usize,
376    ///     ) -> Result<usize, CapacityError> {
377    ///         Ok(input_len)
378    ///     }
379    ///
380    ///     fn reset(
381    ///         &mut self,
382    ///         _output: &mut [u8],
383    ///         _output_index: usize,
384    ///     ) -> Result<usize, Self::Error> {
385    ///         Ok(0)
386    ///     }
387    ///
388    ///     fn transcode(
389    ///         &mut self,
390    ///         input: &[u8],
391    ///         input_index: usize,
392    ///         _output: &mut [u8],
393    ///         _output_index: usize,
394    ///     ) -> Result<TranscodeProgress, Self::Error> {
395    ///         Ok(TranscodeProgress::complete(input.len() - input_index, 0))
396    ///     }
397    ///
398    ///     fn finish(
399    ///         &mut self,
400    ///         _output: &mut [u8],
401    ///         _output_index: usize,
402    ///     ) -> Result<usize, Self::Error> {
403    ///         Ok(0)
404    ///     }
405    /// }
406    ///
407    /// let mut output = TranscodeEncodeOutput::with_capacity(std::io::sink(), 1);
408    /// let mut transcoder = GenericTranscoder;
409    /// let mut map_error = |_| std::io::Error::other("transcode error");
410    /// let _ = output.transcode(
411    ///     &mut transcoder,
412    ///     &mut map_error,
413    ///     &[0_u8],
414    ///     0,
415    ///     1,
416    /// );
417    /// ```
418    pub fn transcode<E, M, Value>(
419        &mut self,
420        encoder: &mut E,
421        map_error: &mut M,
422        input: &[Value],
423        input_index: usize,
424        count: usize,
425    ) -> Result<usize>
426    where
427        E: TranscodeEncoder<Input = Value, Output = O::Item>,
428        M: FnMut(E::Error) -> Error,
429    {
430        let input_end = UncheckedSlice::checked_range_end(
431            input.len(),
432            input_index,
433            count,
434            "encode input range exceeds source buffer",
435        )?;
436        if count == 0 {
437            return Ok(0);
438        }
439        let input = &input[..input_end];
440        let mut read_total = 0;
441        let mut required_spare = NonZeroUsize::MIN;
442        while read_total < count {
443            self.ensure_transcode_spare_capacity(required_spare)?;
444            let (units, output_index, available_output) =
445                self.output.spare_raw_parts_mut();
446            debug_assert!(
447                available_output >= required_spare.get(),
448                "reserved spare buffer is smaller than required encoder output",
449            );
450            let remaining_input = count - read_total;
451            let progress = encoder
452                .transcode(input, input_index + read_total, units, output_index)
453                .map_err(&mut *map_error)?;
454            let progress = validate_encode_progress(
455                progress,
456                input_index + read_total,
457                remaining_input,
458                output_index,
459                available_output,
460            )?;
461            let read = progress.read();
462            let written = progress.written();
463            // SAFETY: The progress bounds check above proved that the encoder
464            // initialized no more than the available spare output window.
465            unsafe {
466                self.output.advance(written);
467            }
468            read_total += read;
469            if progress.is_complete() {
470                return Ok(read_total);
471            }
472            if let TranscodeStatus::NeedOutput { required, .. } =
473                progress.status()
474            {
475                required_spare = required;
476                if read_total == count {
477                    self.ensure_transcode_spare_capacity(required)?;
478                }
479            }
480        }
481        Ok(read_total)
482    }
483
484    /// Finishes the encoder and flushes the wrapped unit output.
485    ///
486    /// This method writes final units directly into the internal spare buffer,
487    /// growing it when [`Transcoder::max_finish_output_len`] exceeds the
488    /// current capacity.
489    ///
490    /// # Parameters
491    ///
492    /// * `encoder` - Encoder whose final units are being collected.
493    /// * `map_error` - Function mapping transcode errors into I/O errors.
494    ///
495    /// # Errors
496    ///
497    /// Returns capacity, transcode finalization, or wrapped output flush
498    /// errors.
499    pub fn finish<E, M, Value>(
500        &mut self,
501        encoder: &mut E,
502        map_error: &mut M,
503    ) -> Result<()>
504    where
505        E: Transcoder<Input = Value, Output = O::Item>,
506        M: FnMut(E::Error) -> Error,
507    {
508        self.finish_to_buffer(encoder, map_error)?;
509        self.output.flush()
510    }
511
512    /// Finishes the encoder while retaining final units in the output buffer.
513    ///
514    /// This method separates encoder finalization from output delivery. It is
515    /// useful when a caller must record successful finalization before a later
516    /// flush can fail. Call [`Self::flush`] to deliver the retained units.
517    ///
518    /// # Parameters
519    ///
520    /// * `encoder` - Encoder whose final units are being collected.
521    /// * `map_error` - Function mapping transcode errors into I/O errors.
522    ///
523    /// # Errors
524    ///
525    /// Returns capacity planning, allocation, or transcoder finalization
526    /// errors. It does not perform output I/O.
527    ///
528    /// # Panics
529    ///
530    /// Panics when `encoder` writes more units than its declared finish bound.
531    pub fn finish_to_buffer<E, M, Value>(
532        &mut self,
533        encoder: &mut E,
534        map_error: &mut M,
535    ) -> Result<()>
536    where
537        E: Transcoder<Input = Value, Output = O::Item>,
538        M: FnMut(E::Error) -> Error,
539    {
540        let required = match encoder.max_finish_output_len() {
541            Ok(required) => required,
542            Err(error) => return Err(capacity_error_to_invalid_data(error)),
543        };
544        self.ensure_spare_capacity(required)?;
545        let (units, output_index, available) =
546            self.output.spare_raw_parts_mut();
547        debug_assert!(
548            available >= required,
549            "insufficient finish capacity reserved in spare output buffer",
550        );
551        let written = encoder
552            .finish(units, output_index)
553            .map_err(&mut *map_error)?;
554        assert!(written <= required, "finish wrote beyond its bound");
555        // SAFETY: The encoder reported initialized units within the spare
556        // range that was reserved above.
557        unsafe {
558            self.output.advance(written);
559        }
560        Ok(())
561    }
562}
563
564impl<O> TranscodeEncodeOutput<O>
565where
566    O: Output<Item = u8> + Seekable<Unit = u8>,
567{
568    /// Flushes pending bytes, then seeks the wrapped byte output.
569    ///
570    /// # Parameters
571    ///
572    /// * `position` - Target seek position.
573    ///
574    /// # Returns
575    ///
576    /// The new stream position reported by the wrapped output.
577    ///
578    /// # Errors
579    ///
580    /// Returns flush or seek errors from the wrapped output.
581    pub fn seek(&mut self, position: SeekFrom) -> Result<u64> {
582        self.output.seek_to(position)
583    }
584}
585
586impl<O> Write for TranscodeEncodeOutput<O>
587where
588    O: Output<Item = u8>,
589{
590    /// Writes raw bytes through the internal buffer.
591    fn write(&mut self, input: &[u8]) -> Result<usize> {
592        Output::write(&mut self.output, input)
593    }
594
595    /// Writes all raw bytes through the internal buffer.
596    fn write_all(&mut self, input: &[u8]) -> Result<()> {
597        let mut written = 0;
598        while written < input.len() {
599            let count = Output::write(&mut self.output, &input[written..])?;
600            if count == 0 {
601                return Err(Error::from(ErrorKind::WriteZero));
602            }
603            assert!(
604                count <= input.len() - written,
605                "Output::write returned a count beyond the input length",
606            );
607            written += count;
608        }
609        Ok(())
610    }
611
612    /// Flushes buffered bytes to the wrapped output.
613    fn flush(&mut self) -> Result<()> {
614        TranscodeEncodeOutput::flush(self)
615    }
616}
617
618impl<O> Seek for TranscodeEncodeOutput<O>
619where
620    O: Output<Item = u8> + Seekable<Unit = u8>,
621{
622    /// Flushes pending bytes, then seeks the wrapped byte output.
623    fn seek(&mut self, position: SeekFrom) -> Result<u64> {
624        self.seek(position)
625    }
626}
627
628impl<O> fmt::Debug for TranscodeEncodeOutput<O>
629where
630    O: Output,
631    O::Item: Copy + Default,
632    BufferedOutput<O>: fmt::Debug,
633{
634    /// Formats this buffered encode output for debugging.
635    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
636        formatter
637            .debug_struct("TranscodeEncodeOutput")
638            .field("output", &self.output)
639            .finish()
640    }
641}
642
643/// Converts an allocation failure into an I/O boundary error.
644fn allocation_to_io_error(error: std::collections::TryReserveError) -> Error {
645    Error::new(ErrorKind::OutOfMemory, error)
646}
647
648/// Maps a streaming capacity error into an I/O error.
649fn capacity_error_to_invalid_data(error: CapacityError) -> Error {
650    Error::new(ErrorKind::InvalidData, error)
651}
652
653/// Maps a one-value codec result into the I/O surface used by this adapter.
654fn map_encode_value_result<T, E, Value>(
655    result: core::result::Result<T, TranscodeEncodeError<E, Value>>,
656    map_error: &mut dyn FnMut(E) -> Error,
657) -> Result<T> {
658    match result {
659        Ok(value) => Ok(value),
660        Err(error) => Err(map_encode_value_error(error, map_error)),
661    }
662}
663
664/// Maps one-value codec encode errors into the I/O surface used by this
665/// adapter.
666#[inline(never)]
667fn map_encode_value_error<E, Value>(
668    error: TranscodeEncodeError<E, Value>,
669    map_error: &mut dyn FnMut(E) -> Error,
670) -> Error {
671    match error {
672        TranscodeEncodeError::Domain(error) => map_error(error.into_source()),
673        TranscodeEncodeError::Unencodable { .. } => {
674            Error::new(ErrorKind::InvalidInput, "codec cannot encode value")
675        }
676        TranscodeEncodeError::Failure(_) => {
677            Error::new(ErrorKind::InvalidInput, "codec output bound overflow")
678        }
679    }
680}