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 qubit_codec::{Codec, CodecTranscodeDecoder};
36///
37/// fn make_decoder<C: Codec>(codec: C) -> CodecTranscodeDecoder<C> {
38///     CodecTranscodeDecoder::new(codec)
39/// }
40/// ```
41#[derive(Debug, Default)]
42pub struct CodecTranscodeDecoder<C> {
43    /// Common buffered decoding engine.
44    engine: TranscodeDecodeEngine<C, CodecTranscodeDecodeHooks>,
45}
46
47impl<C> CodecTranscodeDecoder<C>
48where
49    C: Codec,
50{
51    /// Creates a buffered decoder backed by `codec`.
52    ///
53    /// # Parameters
54    ///
55    /// - `codec`: Low-level codec used to decode values.
56    ///
57    /// # Returns
58    ///
59    /// Returns a buffered decoder adapter for the supplied codec.
60    #[inline]
61    #[must_use]
62    pub fn new(codec: C) -> Self {
63        Self {
64            engine: TranscodeDecodeEngine::new(codec, CodecTranscodeDecodeHooks),
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 CodecTranscodeDecoder<C>
97where
98    C: Codec,
99{
100    type Input = C::Unit;
101    type Output = C::Value;
102    type Error = TranscodeDecodeErrorOf<C>;
103
104    /// Returns an upper bound for decoded values produced from `input_len`
105    /// units.
106    ///
107    /// # Parameters
108    ///
109    /// - `input_len`: Source units the caller plans to decode.
110    ///
111    /// # Returns
112    ///
113    /// Returns a conservative upper bound for decoded values.
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    /// Returns the global maximum values emitted by finishing internal state.
120    ///
121    /// # Returns
122    ///
123    /// Returns the number of values that may still be emitted by finishing
124    /// state.
125    #[inline(always)]
126    fn max_finish_output_len(&self) -> Result<usize, CapacityError> {
127        self.engine.max_finish_output_len()
128    }
129
130    /// Returns the global maximum values emitted when resetting internal state.
131    #[inline(always)]
132    fn max_reset_output_len(&self) -> Result<usize, CapacityError> {
133        self.engine.max_reset_output_len()
134    }
135
136    /// Runs before-reset cleanup for decoder state.
137    #[inline(always)]
138    fn reset(&mut self, output: &mut [C::Value], output_index: usize) -> Result<usize, TranscodeDecodeErrorOf<C>> {
139        self.engine.reset(output, output_index)
140    }
141
142    /// Decodes source units into logical values.
143    ///
144    /// # Parameters
145    ///
146    /// - `input`: Source unit slice.
147    /// - `input_index`: Absolute source index where decoding starts.
148    /// - `output`: Destination value slice.
149    /// - `output_index`: Absolute output value index where writing starts.
150    ///
151    /// # Returns
152    ///
153    /// Returns conversion progress for consumed and written counters.
154    ///
155    /// # Errors
156    ///
157    /// Returns a decode error when indices are invalid or when conversion fails
158    /// under hook policy.
159    #[inline(always)]
160    fn transcode(
161        &mut self,
162        input: &[C::Unit],
163        input_index: usize,
164        output: &mut [C::Value],
165        output_index: usize,
166    ) -> Result<TranscodeProgress, TranscodeDecodeErrorOf<C>> {
167        self.engine.transcode(input, input_index, output, output_index)
168    }
169
170    /// Transcodes an input segment while marking it as the end of the stream.
171    ///
172    /// This forwarding implementation lets the engine apply EOF-specific
173    /// decoder behavior before returning progress to the caller.
174    #[inline(always)]
175    fn transcode_eof(
176        &mut self,
177        input: &[C::Unit],
178        input_index: usize,
179        output: &mut [C::Value],
180        output_index: usize,
181    ) -> Result<TranscodeProgress, TranscodeDecodeErrorOf<C>> {
182        self.engine.transcode_eof(input, input_index, output, output_index)
183    }
184
185    /// Finishes internally retained output after EOF.
186    ///
187    /// # Parameters
188    ///
189    /// - `output`: Destination value slice for final retained values.
190    /// - `output_index`: Absolute output value index where writing starts.
191    ///
192    /// # Returns
193    ///
194    /// Returns the number of values written by finalization.
195    ///
196    /// # Errors
197    ///
198    /// Returns a finish error if finalization cannot complete.
199    #[inline(always)]
200    fn finish(&mut self, output: &mut [C::Value], output_index: usize) -> Result<usize, TranscodeDecodeErrorOf<C>> {
201        self.engine.finish(output, output_index)
202    }
203}
204
205impl<C> TranscodeDecoder for CodecTranscodeDecoder<C>
206where
207    C: Codec,
208{
209    type DecodeError = C::DecodeError;
210}