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::{
13 CapacityError,
14 Codec,
15 TranscodeDecodeErrorOf,
16 TranscodeDecoder,
17 TranscodeProgress,
18 Transcoder,
19};
20
21/// Decodes encoded units into caller-provided value buffers by using a
22/// [`Codec`].
23///
24/// `CodecTranscodeDecoder` is a policy-free bridge from the low-level unchecked
25/// [`Codec`] contract to [`Transcoder`] and [`TranscodeDecoder`]. It
26/// leaves incomplete input tails in the caller-provided input slice while the
27/// stream remains open. Call [`Transcoder::transcode_eof`] after upstream EOF
28/// so codecs can apply their [`Codec::decode_eof`] policy to a trailing prefix.
29///
30/// # Type Parameters
31///
32/// - `C`: Low-level codec used to decode values.
33#[derive(Debug, Default)]
34pub struct CodecTranscodeDecoder<C> {
35 /// Common buffered decoding engine.
36 engine: TranscodeDecodeEngine<C, CodecTranscodeDecodeHooks>,
37}
38
39impl<C> CodecTranscodeDecoder<C>
40where
41 C: Codec,
42{
43 /// Creates a buffered decoder backed by `codec`.
44 ///
45 /// # Parameters
46 ///
47 /// - `codec`: Low-level codec used to decode values.
48 ///
49 /// # Returns
50 ///
51 /// Returns a buffered decoder adapter for the supplied codec.
52 #[inline]
53 #[must_use]
54 pub fn new(codec: C) -> Self {
55 Self {
56 engine: TranscodeDecodeEngine::new(
57 codec,
58 CodecTranscodeDecodeHooks,
59 ),
60 }
61 }
62
63 /// Returns a shared reference to the wrapped codec.
64 #[inline(always)]
65 #[must_use]
66 pub fn codec(&self) -> &C {
67 self.engine.codec()
68 }
69
70 /// Returns a mutable reference to the wrapped codec.
71 ///
72 /// Mutating a codec during an active stream can invalidate that stream's
73 /// assumptions; reset the adapter before continuing with the new codec
74 /// configuration.
75 #[inline(always)]
76 #[must_use]
77 pub fn codec_mut(&mut self) -> &mut C {
78 self.engine.codec_mut()
79 }
80
81 /// Consumes the adapter and returns its wrapped codec.
82 ///
83 /// Any buffered lifecycle state and internal hooks are discarded.
84 #[inline(always)]
85 #[must_use]
86 pub fn into_codec(self) -> C {
87 self.engine.into_parts().0
88 }
89}
90
91impl<C> Transcoder for CodecTranscodeDecoder<C>
92where
93 C: Codec,
94{
95 type Input = C::Unit;
96 type Output = C::Value;
97 type Error = TranscodeDecodeErrorOf<C>;
98
99 /// Returns an upper bound for decoded values produced from `input_len`
100 /// units.
101 ///
102 /// # Parameters
103 ///
104 /// - `input_len`: Source units the caller plans to decode.
105 ///
106 /// # Returns
107 ///
108 /// Returns a conservative upper bound for decoded values.
109 #[inline(always)]
110 fn max_transcode_output_len(
111 &self,
112 input_len: usize,
113 ) -> Result<usize, CapacityError> {
114 self.engine.max_transcode_output_len(input_len)
115 }
116
117 /// Returns the global maximum values emitted by finishing internal state.
118 ///
119 /// # Returns
120 ///
121 /// Returns the number of values that may still be emitted by finishing
122 /// state.
123 #[inline(always)]
124 fn max_finish_output_len(&self) -> Result<usize, CapacityError> {
125 self.engine.max_finish_output_len()
126 }
127
128 /// Returns the global maximum values emitted when resetting internal state.
129 #[inline(always)]
130 fn max_reset_output_len(&self) -> Result<usize, CapacityError> {
131 self.engine.max_reset_output_len()
132 }
133
134 /// Runs before-reset cleanup for decoder state.
135 #[inline(always)]
136 fn reset(
137 &mut self,
138 output: &mut [C::Value],
139 output_index: usize,
140 ) -> Result<usize, TranscodeDecodeErrorOf<C>> {
141 self.engine.reset(output, output_index)
142 }
143
144 /// Decodes source units into logical values.
145 ///
146 /// # Parameters
147 ///
148 /// - `input`: Source unit slice.
149 /// - `input_index`: Absolute source index where decoding starts.
150 /// - `output`: Destination value slice.
151 /// - `output_index`: Absolute output value index where writing starts.
152 ///
153 /// # Returns
154 ///
155 /// Returns conversion progress for consumed and written counters.
156 ///
157 /// # Errors
158 ///
159 /// Returns a decode error when indices are invalid or when conversion fails
160 /// under hook policy.
161 #[inline(always)]
162 fn transcode(
163 &mut self,
164 input: &[C::Unit],
165 input_index: usize,
166 output: &mut [C::Value],
167 output_index: usize,
168 ) -> Result<TranscodeProgress, TranscodeDecodeErrorOf<C>> {
169 self.engine
170 .transcode(input, input_index, output, output_index)
171 }
172
173 #[inline(always)]
174 fn transcode_eof(
175 &mut self,
176 input: &[C::Unit],
177 input_index: usize,
178 output: &mut [C::Value],
179 output_index: usize,
180 ) -> Result<TranscodeProgress, TranscodeDecodeErrorOf<C>> {
181 self.engine
182 .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(
201 &mut self,
202 output: &mut [C::Value],
203 output_index: usize,
204 ) -> Result<usize, TranscodeDecodeErrorOf<C>> {
205 self.engine.finish(output, output_index)
206 }
207}
208
209impl<C> TranscodeDecoder for CodecTranscodeDecoder<C>
210where
211 C: Codec,
212{
213 type DecodeError = C::DecodeError;
214}