qubit_codec/transcode/adapter/codec_transcode_decoder.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 decoder adapter backed by a low-level codec.
9
10use super::super::engine::TranscodeDecodeEngine;
11use super::CodecTranscodeDecodeHooks;
12use crate::CapacityError;
13use crate::Codec;
14use crate::TranscodeDecodeErrorOf;
15use crate::TranscodeDecoder;
16use crate::TranscodeProgress;
17use crate::Transcoder;
18
19/// Decodes encoded units into caller-provided value buffers by using a
20/// [`Codec`].
21///
22/// `CodecTranscodeDecoder` is a policy-free bridge from the low-level unchecked
23/// [`Codec`] contract to [`Transcoder`] and [`TranscodeDecoder`]. It
24/// leaves incomplete input tails in the caller-provided input slice while the
25/// stream remains open. Call [`Transcoder::transcode_eof`] after upstream EOF
26/// so codecs can apply their [`Codec::decode_eof`] policy to a trailing prefix.
27///
28/// # Type Parameters
29///
30/// - `C`: Low-level codec used to decode values.
31///
32/// # Examples
33///
34/// ```
35/// use std::convert::Infallible;
36/// use std::num::NonZeroUsize;
37///
38/// use qubit_codec::Codec;
39/// use qubit_codec::CodecTranscodeDecoder;
40/// use qubit_codec::DecodeFailure;
41/// use qubit_codec::Transcoder;
42///
43/// struct Identity;
44/// impl Codec for Identity {
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 decoder = CodecTranscodeDecoder::new(Identity);
63/// let mut output = [0; 2];
64/// decoder.reset(&mut output, 0).unwrap();
65/// decoder.transcode(&[4, 7], 0, &mut output, 0).unwrap();
66/// assert_eq!(output, [4, 7]);
67/// ```
68#[derive(Debug)]
69pub struct CodecTranscodeDecoder<C> {
70 /// Common buffered decoding engine.
71 engine: TranscodeDecodeEngine<C, CodecTranscodeDecodeHooks>,
72}
73
74impl<C> Default for CodecTranscodeDecoder<C>
75where
76 C: Codec + Default,
77{
78 /// Creates an adapter with the same codec-bound checks as [`Self::new`].
79 ///
80 /// # Returns
81 ///
82 /// Returns a fresh adapter containing a default codec.
83 ///
84 /// # Compile-Time Checks
85 ///
86 /// Fails to compile when the codec declares a zero decode unit bound or
87 /// when [`Codec::MIN_UNITS_PER_VALUE`] exceeds
88 /// [`Codec::MAX_DECODE_UNITS_PER_VALUE`], matching [`Self::new`].
89 ///
90 /// A legal codec can use the default constructor:
91 ///
92 /// ```rust
93 /// use core::convert::Infallible;
94 /// use core::num::NonZeroUsize;
95 /// use qubit_codec::{Codec, CodecTranscodeDecoder, DecodeFailure};
96 ///
97 /// #[derive(Default)]
98 /// struct ByteCodec;
99 /// impl Codec for ByteCodec {
100 /// type Value = u8;
101 /// type Unit = u8;
102 /// type DecodeError = Infallible;
103 /// type EncodeError = Infallible;
104 /// const MIN_UNITS_PER_VALUE: usize = 1;
105 /// const MAX_ENCODE_UNITS_PER_VALUE: usize = 1;
106 /// const MAX_DECODE_UNITS_PER_VALUE: usize = 1;
107 /// unsafe fn decode(&mut self, input: &[u8], index: usize) -> Result<(u8, NonZeroUsize), DecodeFailure<Infallible>> {
108 /// Ok((input[index], NonZeroUsize::MIN))
109 /// }
110 /// unsafe fn encode(&mut self, value: &u8, output: &mut [u8], index: usize) -> Result<usize, Infallible> {
111 /// output[index] = *value;
112 /// Ok(1)
113 /// }
114 /// }
115 /// let _decoder = CodecTranscodeDecoder::<ByteCodec>::default();
116 /// ```
117 ///
118 /// A zero maximum decode width is rejected even when the minimum is valid:
119 ///
120 /// ```compile_fail
121 /// use core::convert::Infallible;
122 /// use core::num::NonZeroUsize;
123 /// use qubit_codec::{Codec, CodecTranscodeDecoder, DecodeFailure};
124 /// #[derive(Default)] struct BadCodec;
125 /// impl Codec for BadCodec {
126 /// type Value = u8; type Unit = u8; type DecodeError = Infallible; type EncodeError = Infallible;
127 /// const MIN_UNITS_PER_VALUE: usize = 1; const MAX_ENCODE_UNITS_PER_VALUE: usize = 1; const MAX_DECODE_UNITS_PER_VALUE: usize = 0;
128 /// unsafe fn decode(&mut self, input: &[u8], index: usize) -> Result<(u8, NonZeroUsize), DecodeFailure<Infallible>> { Ok((input[index], NonZeroUsize::MIN)) }
129 /// unsafe fn encode(&mut self, value: &u8, output: &mut [u8], index: usize) -> Result<usize, Infallible> { output[index] = *value; Ok(1) }
130 /// }
131 /// let _ = CodecTranscodeDecoder::<BadCodec>::default();
132 /// ```
133 #[inline]
134 fn default() -> Self {
135 Self::new(C::default())
136 }
137}
138
139impl<C> CodecTranscodeDecoder<C>
140where
141 C: Codec,
142{
143 /// Creates a buffered decoder backed by `codec`.
144 ///
145 /// # Parameters
146 ///
147 /// - `codec`: Low-level codec used to decode values.
148 ///
149 /// # Returns
150 ///
151 /// Returns a buffered decoder adapter for the supplied codec.
152 #[inline]
153 #[must_use]
154 pub fn new(codec: C) -> Self {
155 Self {
156 engine: TranscodeDecodeEngine::new(codec, CodecTranscodeDecodeHooks),
157 }
158 }
159
160 /// Returns a shared reference to the wrapped codec.
161 ///
162 /// # Returns
163 ///
164 /// A borrow of the codec that remains valid while this adapter is borrowed.
165 #[inline]
166 #[must_use]
167 pub fn codec(&self) -> &C {
168 self.engine.codec()
169 }
170
171 /// Returns a mutable reference to the wrapped codec.
172 ///
173 /// Mutating a codec during an active stream can invalidate that stream's
174 /// assumptions; reset the adapter before continuing with the new codec
175 /// configuration.
176 ///
177 /// # Returns
178 ///
179 /// An exclusive borrow of the wrapped codec; no allocation is performed.
180 #[inline]
181 #[must_use]
182 pub fn codec_mut(&mut self) -> &mut C {
183 self.engine.codec_mut()
184 }
185
186 /// Consumes the adapter and returns its wrapped codec.
187 ///
188 /// Any buffered lifecycle state and internal hooks are discarded.
189 ///
190 /// # Returns
191 ///
192 /// The owned codec, with its codec-specific state preserved.
193 #[inline]
194 #[must_use]
195 pub fn into_codec(self) -> C {
196 let (codec, _) = self.engine.into_parts();
197 codec
198 }
199}
200
201impl<C> Transcoder for CodecTranscodeDecoder<C>
202where
203 C: Codec,
204{
205 /// Encoded units borrowed from the caller input.
206 type Input = C::Unit;
207 /// Decoded values written into caller-provided storage.
208 type Output = C::Value;
209 /// Contract or codec failures reported by the decoding engine.
210 type Error = TranscodeDecodeErrorOf<C>;
211
212 /// Returns an upper bound for decoded values produced from `input_len`
213 /// units.
214 ///
215 /// # Parameters
216 ///
217 /// - `input_len`: Source units the caller plans to decode.
218 ///
219 /// # Returns
220 ///
221 /// Returns a conservative upper bound for decoded values.
222 ///
223 /// # Errors
224 ///
225 /// Returns a capacity error if the requested bound cannot fit in `usize`.
226 #[inline]
227 fn max_transcode_output_len(&self, input_len: usize) -> Result<usize, CapacityError> {
228 self.engine.max_transcode_output_len(input_len)
229 }
230
231 /// Returns the global maximum values emitted by finishing internal state.
232 ///
233 /// # Returns
234 ///
235 /// Returns the number of values that may still be emitted by finishing
236 /// state.
237 ///
238 /// # Errors
239 ///
240 /// Returns a capacity error if the combined finish bound overflows.
241 #[inline]
242 fn max_finish_output_len(&self) -> Result<usize, CapacityError> {
243 self.engine.max_finish_output_len()
244 }
245
246 /// Returns the global maximum values emitted when resetting internal state.
247 ///
248 /// # Returns
249 ///
250 /// The maximum reset output capacity required by the engine.
251 ///
252 /// # Errors
253 ///
254 /// Returns a capacity error if the combined reset bound overflows.
255 #[inline]
256 fn max_reset_output_len(&self) -> Result<usize, CapacityError> {
257 self.engine.max_reset_output_len()
258 }
259
260 /// Runs before-reset cleanup for decoder state.
261 ///
262 /// # Parameters
263 ///
264 /// - `output`: Destination storage for reset values.
265 /// - `output_index`: First destination position to write.
266 ///
267 /// # Returns
268 ///
269 /// The number of reset values written.
270 ///
271 /// # Errors
272 ///
273 /// Returns a contract error for invalid indices or insufficient capacity,
274 /// or a codec error when resetting codec state fails.
275 #[inline]
276 fn reset(&mut self, output: &mut [C::Value], output_index: usize) -> Result<usize, TranscodeDecodeErrorOf<C>> {
277 self.engine.reset(output, output_index)
278 }
279
280 /// Decodes source units into logical values.
281 ///
282 /// # Parameters
283 ///
284 /// - `input`: Source unit slice.
285 /// - `input_index`: Absolute source index where decoding starts.
286 /// - `output`: Destination value slice.
287 /// - `output_index`: Absolute output value index where writing starts.
288 ///
289 /// # Returns
290 ///
291 /// Returns conversion progress for consumed and written counters.
292 ///
293 /// # Errors
294 ///
295 /// Returns a decode error when indices are invalid or when conversion fails
296 /// under hook policy.
297 #[inline]
298 fn transcode(
299 &mut self,
300 input: &[C::Unit],
301 input_index: usize,
302 output: &mut [C::Value],
303 output_index: usize,
304 ) -> Result<TranscodeProgress, TranscodeDecodeErrorOf<C>> {
305 self.engine.transcode(input, input_index, output, output_index)
306 }
307
308 /// Transcodes an input segment while marking it as the end of the stream.
309 ///
310 /// This forwarding implementation lets the engine apply EOF-specific
311 /// decoder behavior before returning progress to the caller.
312 ///
313 /// # Parameters
314 ///
315 /// - `input`: Final source unit slice.
316 /// - `input_index`: First source position to consume.
317 /// - `output`: Destination value storage.
318 /// - `output_index`: First destination position to write.
319 ///
320 /// # Returns
321 ///
322 /// Consumed and written counts and the engine progress status.
323 ///
324 /// # Errors
325 ///
326 /// Returns contract errors for invalid indices or lifecycle transitions,
327 /// or decode errors for malformed or incomplete final input.
328 #[inline]
329 fn transcode_eof(
330 &mut self,
331 input: &[C::Unit],
332 input_index: usize,
333 output: &mut [C::Value],
334 output_index: usize,
335 ) -> Result<TranscodeProgress, TranscodeDecodeErrorOf<C>> {
336 self.engine.transcode_eof(input, input_index, output, output_index)
337 }
338
339 /// Finishes internally retained output after EOF.
340 ///
341 /// # Parameters
342 ///
343 /// - `output`: Destination value slice for final retained values.
344 /// - `output_index`: Absolute output value index where writing starts.
345 ///
346 /// # Returns
347 ///
348 /// Returns the number of values written by finalization.
349 ///
350 /// # Errors
351 ///
352 /// Returns contract errors for invalid indices, insufficient capacity, or
353 /// invalid lifecycle transitions, or a codec error for invalid EOF state.
354 #[inline]
355 fn finish(&mut self, output: &mut [C::Value], output_index: usize) -> Result<usize, TranscodeDecodeErrorOf<C>> {
356 self.engine.finish(output, output_index)
357 }
358}
359
360impl<C> TranscodeDecoder for CodecTranscodeDecoder<C>
361where
362 C: Codec,
363{
364 /// Codec-specific failure retained by the decoder error wrapper.
365 type DecodeError = C::DecodeError;
366}