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