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