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