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 self.engine.into_parts().0
132 }
133}
134
135impl<C> Transcoder for CodecTranscodeDecoder<C>
136where
137 C: Codec,
138{
139 /// Encoded units borrowed from the caller input.
140 type Input = C::Unit;
141 /// Decoded values written into caller-provided storage.
142 type Output = C::Value;
143 /// Contract or codec failures reported by the decoding engine.
144 type Error = TranscodeDecodeErrorOf<C>;
145
146 /// Returns an upper bound for decoded values produced from `input_len`
147 /// units.
148 ///
149 /// # Parameters
150 ///
151 /// - `input_len`: Source units the caller plans to decode.
152 ///
153 /// # Returns
154 ///
155 /// Returns a conservative upper bound for decoded values.
156 ///
157 /// # Errors
158 ///
159 /// Returns a capacity error if the requested bound cannot fit in `usize`.
160 #[inline]
161 fn max_transcode_output_len(&self, input_len: usize) -> Result<usize, CapacityError> {
162 self.engine.max_transcode_output_len(input_len)
163 }
164
165 /// Returns the global maximum values emitted by finishing internal state.
166 ///
167 /// # Returns
168 ///
169 /// Returns the number of values that may still be emitted by finishing
170 /// state.
171 ///
172 /// # Errors
173 ///
174 /// Returns a capacity error if the combined finish bound overflows.
175 #[inline]
176 fn max_finish_output_len(&self) -> Result<usize, CapacityError> {
177 self.engine.max_finish_output_len()
178 }
179
180 /// Returns the global maximum values emitted when resetting internal state.
181 ///
182 /// # Returns
183 ///
184 /// The maximum reset output capacity required by the engine.
185 ///
186 /// # Errors
187 ///
188 /// Returns a capacity error if the combined reset bound overflows.
189 #[inline]
190 fn max_reset_output_len(&self) -> Result<usize, CapacityError> {
191 self.engine.max_reset_output_len()
192 }
193
194 /// Runs before-reset cleanup for decoder state.
195 ///
196 /// # Parameters
197 ///
198 /// - `output`: Destination storage for reset values.
199 /// - `output_index`: First destination position to write.
200 ///
201 /// # Returns
202 ///
203 /// The number of reset values written.
204 ///
205 /// # Errors
206 ///
207 /// Returns a contract error for invalid indices or insufficient capacity,
208 /// or a codec error when resetting codec state fails.
209 fn reset(&mut self, output: &mut [C::Value], output_index: usize) -> Result<usize, TranscodeDecodeErrorOf<C>> {
210 self.engine.reset(output, output_index)
211 }
212
213 /// Decodes source units into logical values.
214 ///
215 /// # Parameters
216 ///
217 /// - `input`: Source unit slice.
218 /// - `input_index`: Absolute source index where decoding starts.
219 /// - `output`: Destination value slice.
220 /// - `output_index`: Absolute output value index where writing starts.
221 ///
222 /// # Returns
223 ///
224 /// Returns conversion progress for consumed and written counters.
225 ///
226 /// # Errors
227 ///
228 /// Returns a decode error when indices are invalid or when conversion fails
229 /// under hook policy.
230 fn transcode(
231 &mut self,
232 input: &[C::Unit],
233 input_index: usize,
234 output: &mut [C::Value],
235 output_index: usize,
236 ) -> Result<TranscodeProgress, TranscodeDecodeErrorOf<C>> {
237 self.engine.transcode(input, input_index, output, output_index)
238 }
239
240 /// Transcodes an input segment while marking it as the end of the stream.
241 ///
242 /// This forwarding implementation lets the engine apply EOF-specific
243 /// decoder behavior before returning progress to the caller.
244 ///
245 /// # Parameters
246 ///
247 /// - `input`: Final source unit slice.
248 /// - `input_index`: First source position to consume.
249 /// - `output`: Destination value storage.
250 /// - `output_index`: First destination position to write.
251 ///
252 /// # Returns
253 ///
254 /// Consumed and written counts and the engine progress status.
255 ///
256 /// # Errors
257 ///
258 /// Returns contract errors for invalid indices or lifecycle transitions,
259 /// or decode errors for malformed or incomplete final input.
260 fn transcode_eof(
261 &mut self,
262 input: &[C::Unit],
263 input_index: usize,
264 output: &mut [C::Value],
265 output_index: usize,
266 ) -> Result<TranscodeProgress, TranscodeDecodeErrorOf<C>> {
267 self.engine.transcode_eof(input, input_index, output, output_index)
268 }
269
270 /// Finishes internally retained output after EOF.
271 ///
272 /// # Parameters
273 ///
274 /// - `output`: Destination value slice for final retained values.
275 /// - `output_index`: Absolute output value index where writing starts.
276 ///
277 /// # Returns
278 ///
279 /// Returns the number of values written by finalization.
280 ///
281 /// # Errors
282 ///
283 /// Returns contract errors for invalid indices, insufficient capacity, or
284 /// invalid lifecycle transitions, or a codec error for invalid EOF state.
285 fn finish(&mut self, output: &mut [C::Value], output_index: usize) -> Result<usize, TranscodeDecodeErrorOf<C>> {
286 self.engine.finish(output, output_index)
287 }
288}
289
290impl<C> TranscodeDecoder for CodecTranscodeDecoder<C>
291where
292 C: Codec,
293{
294 /// Codec-specific failure retained by the decoder error wrapper.
295 type DecodeError = C::DecodeError;
296}