Skip to main content

qubit_codec/transcode/adapter/
codec_transcode_encoder.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 encoder adapter backed by a low-level codec.
9
10use super::CodecTranscodeEncodeHooks;
11use crate::{
12    CapacityError,
13    Codec,
14    CodecEncodeError,
15    TranscodeEncodeEngine,
16    TranscodeEncodeEngineError,
17    TranscodeEncoder,
18    TranscodeError,
19    TranscodeProgress,
20    Transcoder,
21};
22
23/// Encodes values into caller-provided output units by using a [`Codec`].
24///
25/// `CodecTranscodeEncoder` is the default bridge from the low-level unchecked
26/// [`Codec`] contract to the buffered [`Transcoder`] and
27/// [`TranscodeEncoder`] contracts. It encodes complete values only; when the
28/// remaining output capacity is smaller than `codec.encode_len(value)`, it
29/// stops before consuming that input value and reports
30/// [`crate::TranscodeStatus::NeedOutput`].
31///
32/// # Type Parameters
33///
34/// - `C`: Low-level codec used to encode values.
35#[derive(Debug)]
36pub struct CodecTranscodeEncoder<C> {
37    /// Common buffered encoding engine.
38    engine: TranscodeEncodeEngine<C, CodecTranscodeEncodeHooks>,
39}
40
41impl<C> CodecTranscodeEncoder<C>
42where
43    C: Codec,
44{
45    /// Creates a buffered encoder backed by `codec`.
46    ///
47    /// # Parameters
48    ///
49    /// - `codec`: Low-level codec used to encode values.
50    ///
51    /// # Returns
52    ///
53    /// Returns a buffered encoder adapter for the supplied codec.
54    #[inline]
55    #[must_use]
56    pub fn new(codec: C) -> Self {
57        Self {
58            engine: TranscodeEncodeEngine::new(
59                codec,
60                CodecTranscodeEncodeHooks,
61            ),
62        }
63    }
64}
65
66impl<C> Transcoder<C::Value, C::Unit> for CodecTranscodeEncoder<C>
67where
68    C: Codec,
69{
70    type Error = CodecEncodeError<C::EncodeError>;
71
72    /// Gets the maximum number of output units needed for `input_len`
73    /// values.
74    ///
75    /// # Parameters
76    ///
77    /// - `input_len`: Logical input values the caller plans to encode.
78    ///
79    /// # Returns
80    ///
81    /// a conservative upper bound for output units.
82    #[inline(always)]
83    fn max_output_len(&self, input_len: usize) -> Result<usize, CapacityError> {
84        self.engine.max_output_len(input_len)
85    }
86
87    /// Gets the maximum units emitted when resetting internal state.
88    ///
89    /// # Returns
90    ///
91    /// the maximum units emitted when resetting internal state.
92    #[inline(always)]
93    fn max_reset_output_len(&self) -> Result<usize, CapacityError> {
94        self.engine.max_reset_output_len()
95    }
96
97    /// Gets the maximum units emitted by finishing internal state.
98    ///
99    /// # Returns
100    ///
101    /// the number of units that may be emitted by finishing state.
102    #[inline(always)]
103    fn max_finish_output_len(&self) -> Result<usize, CapacityError> {
104        self.engine.max_finish_output_len()
105    }
106
107    /// Runs before-reset cleanup and emits stream-start output.
108    #[inline(always)]
109    fn reset(
110        &mut self,
111        output: &mut [C::Unit],
112        output_index: usize,
113    ) -> Result<usize, TranscodeError<Self::Error>> {
114        self.engine
115            .reset(output, output_index)
116            .map_err(|error| error.map_domain(flatten_encode_engine_error))
117    }
118
119    /// Encodes values into the supplied output buffer.
120    ///
121    /// # Parameters
122    ///
123    /// - `input`: Input value slice.
124    /// - `input_index`: Absolute input index where encoding starts.
125    /// - `output`: Destination unit slice.
126    /// - `output_index`: Absolute output index where writing starts.
127    ///
128    /// # Returns
129    ///
130    /// Returns conversion progress for consumed input and produced output
131    /// units.
132    ///
133    /// # Errors
134    ///
135    /// Returns an encode error when indices are invalid or when encoding cannot
136    /// continue under current policy.
137    #[inline(always)]
138    fn transcode(
139        &mut self,
140        input: &[C::Value],
141        input_index: usize,
142        output: &mut [C::Unit],
143        output_index: usize,
144    ) -> Result<TranscodeProgress, TranscodeError<Self::Error>> {
145        self.engine
146            .transcode(input, input_index, output, output_index)
147            .map_err(|error| error.map_domain(flatten_encode_engine_error))
148    }
149
150    /// Finishes internally retained output after EOF.
151    ///
152    /// # Parameters
153    ///
154    /// - `output`: Destination unit slice for finalization output.
155    /// - `output_index`: Absolute output index where writing starts.
156    ///
157    /// # Returns
158    ///
159    /// Returns the number of units written by finalization.
160    ///
161    /// # Errors
162    ///
163    /// Returns a finish error if retained output cannot be fully emitted.
164    #[inline(always)]
165    fn finish(
166        &mut self,
167        output: &mut [C::Unit],
168        output_index: usize,
169    ) -> Result<usize, TranscodeError<Self::Error>> {
170        self.engine
171            .finish(output, output_index)
172            .map_err(|error| error.map_domain(flatten_encode_engine_error))
173    }
174}
175
176impl<C> TranscodeEncoder<C::Value, C::Unit> for CodecTranscodeEncoder<C>
177where
178    C: Codec,
179{
180    // empty
181}
182
183impl<C> Default for CodecTranscodeEncoder<C>
184where
185    C: Codec + Default,
186{
187    /// Creates a default codec-backed buffered encoder.
188    ///
189    /// # Returns
190    ///
191    /// Returns an encoder backed by `C::default()`.
192    #[inline(always)]
193    fn default() -> Self {
194        Self::new(C::default())
195    }
196}
197
198#[inline(always)]
199fn flatten_encode_engine_error<E>(
200    error: TranscodeEncodeEngineError<E, CodecEncodeError<E>>,
201) -> CodecEncodeError<E> {
202    match error {
203        TranscodeEncodeEngineError::Codec(error)
204        | TranscodeEncodeEngineError::Hook(error) => error,
205    }
206}