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}