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, Default)]
69pub struct CodecTranscodeDecoder<C> {
70    /// Common buffered decoding engine.
71    engine: TranscodeDecodeEngine<C, CodecTranscodeDecodeHooks>,
72}
73
74impl<C> CodecTranscodeDecoder<C>
75where
76    C: Codec,
77{
78    /// Creates a buffered decoder backed by `codec`.
79    ///
80    /// # Parameters
81    ///
82    /// - `codec`: Low-level codec used to decode values.
83    ///
84    /// # Returns
85    ///
86    /// Returns a buffered decoder adapter for the supplied codec.
87    #[inline]
88    #[must_use]
89    pub fn new(codec: C) -> Self {
90        Self {
91            engine: TranscodeDecodeEngine::new(codec, CodecTranscodeDecodeHooks),
92        }
93    }
94
95    /// Returns a shared reference to the wrapped codec.
96    ///
97    /// # Returns
98    ///
99    /// A borrow of the codec that remains valid while this adapter is borrowed.
100    #[inline]
101    #[must_use]
102    pub fn codec(&self) -> &C {
103        self.engine.codec()
104    }
105
106    /// Returns a mutable reference to the wrapped codec.
107    ///
108    /// Mutating a codec during an active stream can invalidate that stream's
109    /// assumptions; reset the adapter before continuing with the new codec
110    /// configuration.
111    ///
112    /// # Returns
113    ///
114    /// An exclusive borrow of the wrapped codec; no allocation is performed.
115    #[inline]
116    #[must_use]
117    pub fn codec_mut(&mut self) -> &mut C {
118        self.engine.codec_mut()
119    }
120
121    /// Consumes the adapter and returns its wrapped codec.
122    ///
123    /// Any buffered lifecycle state and internal hooks are discarded.
124    ///
125    /// # Returns
126    ///
127    /// The owned codec, with its codec-specific state preserved.
128    #[inline]
129    #[must_use]
130    pub fn into_codec(self) -> C {
131        let (codec, _) = self.engine.into_parts();
132        codec
133    }
134}
135
136impl<C> Transcoder for CodecTranscodeDecoder<C>
137where
138    C: Codec,
139{
140    /// Encoded units borrowed from the caller input.
141    type Input = C::Unit;
142    /// Decoded values written into caller-provided storage.
143    type Output = C::Value;
144    /// Contract or codec failures reported by the decoding engine.
145    type Error = TranscodeDecodeErrorOf<C>;
146
147    /// Returns an upper bound for decoded values produced from `input_len`
148    /// units.
149    ///
150    /// # Parameters
151    ///
152    /// - `input_len`: Source units the caller plans to decode.
153    ///
154    /// # Returns
155    ///
156    /// Returns a conservative upper bound for decoded values.
157    ///
158    /// # Errors
159    ///
160    /// Returns a capacity error if the requested bound cannot fit in `usize`.
161    #[inline]
162    fn max_transcode_output_len(&self, input_len: usize) -> Result<usize, CapacityError> {
163        self.engine.max_transcode_output_len(input_len)
164    }
165
166    /// Returns the global maximum values emitted by finishing internal state.
167    ///
168    /// # Returns
169    ///
170    /// Returns the number of values that may still be emitted by finishing
171    /// state.
172    ///
173    /// # Errors
174    ///
175    /// Returns a capacity error if the combined finish bound overflows.
176    #[inline]
177    fn max_finish_output_len(&self) -> Result<usize, CapacityError> {
178        self.engine.max_finish_output_len()
179    }
180
181    /// Returns the global maximum values emitted when resetting internal state.
182    ///
183    /// # Returns
184    ///
185    /// The maximum reset output capacity required by the engine.
186    ///
187    /// # Errors
188    ///
189    /// Returns a capacity error if the combined reset bound overflows.
190    #[inline]
191    fn max_reset_output_len(&self) -> Result<usize, CapacityError> {
192        self.engine.max_reset_output_len()
193    }
194
195    /// Runs before-reset cleanup for decoder state.
196    ///
197    /// # Parameters
198    ///
199    /// - `output`: Destination storage for reset values.
200    /// - `output_index`: First destination position to write.
201    ///
202    /// # Returns
203    ///
204    /// The number of reset values written.
205    ///
206    /// # Errors
207    ///
208    /// Returns a contract error for invalid indices or insufficient capacity,
209    /// or a codec error when resetting codec state fails.
210    #[inline]
211    fn reset(&mut self, output: &mut [C::Value], output_index: usize) -> Result<usize, TranscodeDecodeErrorOf<C>> {
212        self.engine.reset(output, output_index)
213    }
214
215    /// Decodes source units into logical values.
216    ///
217    /// # Parameters
218    ///
219    /// - `input`: Source unit slice.
220    /// - `input_index`: Absolute source index where decoding starts.
221    /// - `output`: Destination value slice.
222    /// - `output_index`: Absolute output value index where writing starts.
223    ///
224    /// # Returns
225    ///
226    /// Returns conversion progress for consumed and written counters.
227    ///
228    /// # Errors
229    ///
230    /// Returns a decode error when indices are invalid or when conversion fails
231    /// under hook policy.
232    #[inline]
233    fn transcode(
234        &mut self,
235        input: &[C::Unit],
236        input_index: usize,
237        output: &mut [C::Value],
238        output_index: usize,
239    ) -> Result<TranscodeProgress, TranscodeDecodeErrorOf<C>> {
240        self.engine.transcode(input, input_index, output, output_index)
241    }
242
243    /// Transcodes an input segment while marking it as the end of the stream.
244    ///
245    /// This forwarding implementation lets the engine apply EOF-specific
246    /// decoder behavior before returning progress to the caller.
247    ///
248    /// # Parameters
249    ///
250    /// - `input`: Final source unit slice.
251    /// - `input_index`: First source position to consume.
252    /// - `output`: Destination value storage.
253    /// - `output_index`: First destination position to write.
254    ///
255    /// # Returns
256    ///
257    /// Consumed and written counts and the engine progress status.
258    ///
259    /// # Errors
260    ///
261    /// Returns contract errors for invalid indices or lifecycle transitions,
262    /// or decode errors for malformed or incomplete final input.
263    #[inline]
264    fn transcode_eof(
265        &mut self,
266        input: &[C::Unit],
267        input_index: usize,
268        output: &mut [C::Value],
269        output_index: usize,
270    ) -> Result<TranscodeProgress, TranscodeDecodeErrorOf<C>> {
271        self.engine.transcode_eof(input, input_index, output, output_index)
272    }
273
274    /// Finishes internally retained output after EOF.
275    ///
276    /// # Parameters
277    ///
278    /// - `output`: Destination value slice for final retained values.
279    /// - `output_index`: Absolute output value index where writing starts.
280    ///
281    /// # Returns
282    ///
283    /// Returns the number of values written by finalization.
284    ///
285    /// # Errors
286    ///
287    /// Returns contract errors for invalid indices, insufficient capacity, or
288    /// invalid lifecycle transitions, or a codec error for invalid EOF state.
289    #[inline]
290    fn finish(&mut self, output: &mut [C::Value], output_index: usize) -> Result<usize, TranscodeDecodeErrorOf<C>> {
291        self.engine.finish(output, output_index)
292    }
293}
294
295impl<C> TranscodeDecoder for CodecTranscodeDecoder<C>
296where
297    C: Codec,
298{
299    /// Codec-specific failure retained by the decoder error wrapper.
300    type DecodeError = C::DecodeError;
301}