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 core::convert::Infallible;
36/// use core::num::NonZeroUsize;
37///
38/// use qubit_codec::Codec;
39/// use qubit_codec::CodecTranscodeEncoder;
40/// use qubit_codec::DecodeFailure;
41/// use qubit_codec::Transcoder;
42///
43/// # struct ByteCodec;
44/// # impl Codec for ByteCodec {
45/// # type Value = u8;
46/// # type Unit = u8;
47/// # type DecodeError = Infallible;
48/// # type EncodeError = Infallible;
49/// # const MIN_UNITS_PER_VALUE: usize = 1;
50/// # const MAX_DECODE_UNITS_PER_VALUE: usize = 1;
51/// # const MAX_ENCODE_UNITS_PER_VALUE: usize = 1;
52/// # unsafe fn decode(&mut self, input: &[u8], index: usize)
53/// # -> Result<(u8, NonZeroUsize), DecodeFailure<Infallible>> {
54/// # Ok((input[index], NonZeroUsize::new(1).unwrap()))
55/// # }
56/// # unsafe fn encode(&mut self, value: &u8, output: &mut [u8], index: usize)
57/// # -> Result<usize, Infallible> {
58/// # output[index] = *value;
59/// # Ok(1)
60/// # }
61/// # }
62/// let mut encoder = CodecTranscodeEncoder::new(ByteCodec);
63/// let mut output = [0; 2];
64/// assert_eq!(encoder.reset(&mut output, 0).unwrap(), 0);
65/// let progress = encoder.transcode(&[7, 9], 0, &mut output, 0).unwrap();
66/// assert_eq!(progress.written(), 2);
67/// assert_eq!(output, [7, 9]);
68/// ```
69#[derive(Debug)]
70pub struct CodecTranscodeEncoder<C> {
71 /// Common buffered encoding engine.
72 engine: TranscodeEncodeEngine<C, CodecTranscodeEncodeHooks>,
73}
74
75impl<C> CodecTranscodeEncoder<C>
76where
77 C: Codec,
78{
79 /// Creates a buffered encoder backed by `codec`.
80 ///
81 /// # Parameters
82 ///
83 /// - `codec`: Low-level codec used to encode values.
84 ///
85 /// # Returns
86 ///
87 /// Returns a buffered encoder adapter for the supplied codec.
88 #[inline]
89 #[must_use]
90 pub fn new(codec: C) -> Self {
91 Self {
92 engine: TranscodeEncodeEngine::new(codec, CodecTranscodeEncodeHooks),
93 }
94 }
95
96 /// Borrows the codec without allocating or changing stream state.
97 ///
98 /// # Returns
99 ///
100 /// The wrapped codec, borrowed for the lifetime of `self`.
101 #[inline]
102 #[must_use]
103 pub fn codec(&self) -> &C {
104 self.engine.codec()
105 }
106
107 /// Returns a mutable reference to the wrapped codec.
108 ///
109 /// Mutating a codec during an active stream can invalidate that stream's
110 /// assumptions; reset the adapter before continuing with the new codec
111 /// configuration.
112 ///
113 /// # Returns
114 ///
115 /// An exclusive borrow of the wrapped codec tied to `self`.
116 #[inline]
117 #[must_use]
118 pub fn codec_mut(&mut self) -> &mut C {
119 self.engine.codec_mut()
120 }
121
122 /// Consumes the adapter and returns its wrapped codec.
123 ///
124 /// Any buffered lifecycle state and internal hooks are discarded.
125 ///
126 /// # Returns
127 ///
128 /// The owned codec, without resetting or finishing it.
129 #[inline]
130 #[must_use]
131 pub fn into_codec(self) -> C {
132 self.engine.into_parts().0
133 }
134}
135
136impl<C> Transcoder for CodecTranscodeEncoder<C>
137where
138 C: Codec,
139{
140 /// Values accepted by the wrapped codec.
141 type Input = C::Value;
142 /// Representation units emitted by the wrapped codec.
143 type Output = C::Unit;
144 /// Domain, contract, and codec failures during buffered encoding.
145 type Error = TranscodeEncodeErrorOf<C>;
146
147 /// Gets the maximum number of output units needed for `input_len`
148 /// values.
149 ///
150 /// # Parameters
151 ///
152 /// - `input_len`: Logical input values the caller plans to encode.
153 ///
154 /// # Returns
155 ///
156 /// a conservative upper bound for output units.
157 ///
158 /// # Errors
159 ///
160 /// Returns [`CapacityError`] if the engine cannot represent the bound in
161 /// `usize`.
162 #[inline]
163 fn max_transcode_output_len(&self, input_len: usize) -> Result<usize, CapacityError> {
164 self.engine.max_transcode_output_len(input_len)
165 }
166
167 /// Gets the global maximum units emitted when resetting internal state.
168 ///
169 /// # Returns
170 ///
171 /// the maximum units emitted when resetting internal state.
172 ///
173 /// # Errors
174 ///
175 /// Returns [`CapacityError`] if the engine cannot represent the bound in
176 /// `usize`.
177 #[inline]
178 fn max_reset_output_len(&self) -> Result<usize, CapacityError> {
179 self.engine.max_reset_output_len()
180 }
181
182 /// Gets the global maximum units emitted by finishing internal state.
183 ///
184 /// # Returns
185 ///
186 /// the number of units that may be emitted by finishing state.
187 ///
188 /// # Errors
189 ///
190 /// Returns [`CapacityError`] if the engine cannot represent the bound in
191 /// `usize`.
192 #[inline]
193 fn max_finish_output_len(&self) -> Result<usize, CapacityError> {
194 self.engine.max_finish_output_len()
195 }
196
197 /// Runs before-reset cleanup and emits stream-start output.
198 ///
199 /// # Parameters
200 ///
201 /// - `output`: Destination for codec reset units.
202 /// - `output_index`: Start position in `output`.
203 ///
204 /// # Returns
205 ///
206 /// The number of reset units written; previous lifecycle state is
207 /// discarded.
208 ///
209 /// # Errors
210 ///
211 /// Returns an error for an invalid index, insufficient reset capacity,
212 /// a violated codec contract, or a codec reset failure.
213 fn reset(&mut self, output: &mut [C::Unit], output_index: usize) -> Result<usize, TranscodeEncodeErrorOf<C>> {
214 self.engine.reset(output, output_index)
215 }
216
217 /// Encodes values into the supplied output buffer.
218 ///
219 /// # Parameters
220 ///
221 /// - `input`: Input value slice.
222 /// - `input_index`: Absolute input index where encoding starts.
223 /// - `output`: Destination unit slice.
224 /// - `output_index`: Absolute output index where writing starts.
225 ///
226 /// # Returns
227 ///
228 /// Returns conversion progress for consumed input and produced output
229 /// units.
230 ///
231 /// # Errors
232 ///
233 /// Returns an encode error when indices are invalid or when encoding cannot
234 /// continue under current policy.
235 fn transcode(
236 &mut self,
237 input: &[C::Value],
238 input_index: usize,
239 output: &mut [C::Unit],
240 output_index: usize,
241 ) -> Result<TranscodeProgress, TranscodeEncodeErrorOf<C>> {
242 self.engine.transcode(input, input_index, output, output_index)
243 }
244
245 /// Finishes internally retained output after EOF.
246 ///
247 /// # Parameters
248 ///
249 /// - `output`: Destination unit slice for finalization output.
250 /// - `output_index`: Absolute output index where writing starts.
251 ///
252 /// # Returns
253 ///
254 /// Returns the number of units written by finalization.
255 ///
256 /// # Errors
257 ///
258 /// Returns a finish error if retained output cannot be fully emitted.
259 fn finish(&mut self, output: &mut [C::Unit], output_index: usize) -> Result<usize, TranscodeEncodeErrorOf<C>> {
260 self.engine.finish(output, output_index)
261 }
262}
263
264impl<C> TranscodeEncoder for CodecTranscodeEncoder<C>
265where
266 C: Codec,
267{
268 /// Codec-specific encoding failure carried by the adapter.
269 type EncodeError = C::EncodeError;
270}
271
272impl<C> Default for CodecTranscodeEncoder<C>
273where
274 C: Codec + Default,
275{
276 /// Creates a default codec-backed buffered encoder.
277 ///
278 /// # Returns
279 ///
280 /// Returns an encoder backed by `C::default()`.
281 fn default() -> Self {
282 Self::new(C::default())
283 }
284}