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