Skip to main content

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}