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}