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#[derive(Debug, Default)]
32pub struct CodecTranscodeDecoder<C> {
33 /// Common buffered decoding engine.
34 engine: TranscodeDecodeEngine<C, CodecTranscodeDecodeHooks>,
35}
36
37impl<C> CodecTranscodeDecoder<C>
38where
39 C: Codec,
40{
41 /// Creates a buffered decoder backed by `codec`.
42 ///
43 /// # Parameters
44 ///
45 /// - `codec`: Low-level codec used to decode values.
46 ///
47 /// # Returns
48 ///
49 /// Returns a buffered decoder adapter for the supplied codec.
50 #[inline]
51 #[must_use]
52 pub fn new(codec: C) -> Self {
53 Self {
54 engine: TranscodeDecodeEngine::new(codec, CodecTranscodeDecodeHooks),
55 }
56 }
57
58 /// Returns a shared reference to the wrapped codec.
59 #[inline(always)]
60 #[must_use]
61 pub fn codec(&self) -> &C {
62 self.engine.codec()
63 }
64
65 /// Returns a mutable reference to the wrapped codec.
66 ///
67 /// Mutating a codec during an active stream can invalidate that stream's
68 /// assumptions; reset the adapter before continuing with the new codec
69 /// configuration.
70 #[inline(always)]
71 #[must_use]
72 pub fn codec_mut(&mut self) -> &mut C {
73 self.engine.codec_mut()
74 }
75
76 /// Consumes the adapter and returns its wrapped codec.
77 ///
78 /// Any buffered lifecycle state and internal hooks are discarded.
79 #[inline(always)]
80 #[must_use]
81 pub fn into_codec(self) -> C {
82 self.engine.into_parts().0
83 }
84}
85
86impl<C> Transcoder for CodecTranscodeDecoder<C>
87where
88 C: Codec,
89{
90 type Input = C::Unit;
91 type Output = C::Value;
92 type Error = TranscodeDecodeErrorOf<C>;
93
94 /// Returns an upper bound for decoded values produced from `input_len`
95 /// units.
96 ///
97 /// # Parameters
98 ///
99 /// - `input_len`: Source units the caller plans to decode.
100 ///
101 /// # Returns
102 ///
103 /// Returns a conservative upper bound for decoded values.
104 #[inline(always)]
105 fn max_transcode_output_len(&self, input_len: usize) -> Result<usize, CapacityError> {
106 self.engine.max_transcode_output_len(input_len)
107 }
108
109 /// Returns the global maximum values emitted by finishing internal state.
110 ///
111 /// # Returns
112 ///
113 /// Returns the number of values that may still be emitted by finishing
114 /// state.
115 #[inline(always)]
116 fn max_finish_output_len(&self) -> Result<usize, CapacityError> {
117 self.engine.max_finish_output_len()
118 }
119
120 /// Returns the global maximum values emitted when resetting internal state.
121 #[inline(always)]
122 fn max_reset_output_len(&self) -> Result<usize, CapacityError> {
123 self.engine.max_reset_output_len()
124 }
125
126 /// Runs before-reset cleanup for decoder state.
127 #[inline(always)]
128 fn reset(&mut self, output: &mut [C::Value], output_index: usize) -> Result<usize, TranscodeDecodeErrorOf<C>> {
129 self.engine.reset(output, output_index)
130 }
131
132 /// Decodes source units into logical values.
133 ///
134 /// # Parameters
135 ///
136 /// - `input`: Source unit slice.
137 /// - `input_index`: Absolute source index where decoding starts.
138 /// - `output`: Destination value slice.
139 /// - `output_index`: Absolute output value index where writing starts.
140 ///
141 /// # Returns
142 ///
143 /// Returns conversion progress for consumed and written counters.
144 ///
145 /// # Errors
146 ///
147 /// Returns a decode error when indices are invalid or when conversion fails
148 /// under hook policy.
149 #[inline(always)]
150 fn transcode(
151 &mut self,
152 input: &[C::Unit],
153 input_index: usize,
154 output: &mut [C::Value],
155 output_index: usize,
156 ) -> Result<TranscodeProgress, TranscodeDecodeErrorOf<C>> {
157 self.engine.transcode(input, input_index, output, output_index)
158 }
159
160 #[inline(always)]
161 fn transcode_eof(
162 &mut self,
163 input: &[C::Unit],
164 input_index: usize,
165 output: &mut [C::Value],
166 output_index: usize,
167 ) -> Result<TranscodeProgress, TranscodeDecodeErrorOf<C>> {
168 self.engine.transcode_eof(input, input_index, output, output_index)
169 }
170
171 /// Finishes internally retained output after EOF.
172 ///
173 /// # Parameters
174 ///
175 /// - `output`: Destination value slice for final retained values.
176 /// - `output_index`: Absolute output value index where writing starts.
177 ///
178 /// # Returns
179 ///
180 /// Returns the number of values written by finalization.
181 ///
182 /// # Errors
183 ///
184 /// Returns a finish error if finalization cannot complete.
185 #[inline(always)]
186 fn finish(&mut self, output: &mut [C::Value], output_index: usize) -> Result<usize, TranscodeDecodeErrorOf<C>> {
187 self.engine.finish(output, output_index)
188 }
189}
190
191impl<C> TranscodeDecoder for CodecTranscodeDecoder<C>
192where
193 C: Codec,
194{
195 type DecodeError = C::DecodeError;
196}