qubit_codec/value/codec_value_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//! Value decoder adapter backed by a low-level codec.
9
10use core::fmt;
11
12use super::{
13 DecodeLifecycleOutput,
14 DecodeLifecycleProgress,
15 ValueDecoder,
16};
17use crate::{
18 Codec,
19 TranscodeDecodeErrorOf,
20 TranscodeFailure,
21 codec::assert_unit_bounds,
22 value::codec_value_lifecycle::decode_exact_complete_value,
23};
24
25/// Decodes one encoded unit slice into one owned value by using a [`Codec`].
26///
27/// `CodecValueDecoder` is the default bridge from the low-level unchecked
28/// [`Codec`] contract to the convenience-layer [`ValueDecoder`] contract. The
29/// supplied input slice must contain exactly one encoded value. The adapter
30/// runs the complete decode lifecycle, including [`Codec::decode_finish`],
31/// before returning the decoded value.
32///
33/// # Type Parameters
34///
35/// - `C`: Low-level codec used to decode one value.
36pub struct CodecValueDecoder<C>
37where
38 C: Codec,
39{
40 /// Low-level codec used for one-value decoding.
41 codec: C,
42}
43
44impl<C> CodecValueDecoder<C>
45where
46 C: Codec,
47{
48 /// Creates a decoder backed by `codec`.
49 ///
50 /// # Parameters
51 ///
52 /// - `codec`: Low-level codec used to decode one value.
53 ///
54 /// # Returns
55 ///
56 /// Returns a value decoder adapter for the supplied codec.
57 ///
58 /// # Panics
59 ///
60 /// Panics when the supplied codec declares invalid unit bounds or an
61 /// invalid decode unit bounds.
62 #[inline]
63 #[must_use]
64 pub fn new(codec: C) -> Self {
65 assert_unit_bounds::<C>();
66 Self { codec }
67 }
68
69 /// Returns a shared reference to the wrapped codec.
70 #[inline(always)]
71 #[must_use]
72 pub const fn codec(&self) -> &C {
73 &self.codec
74 }
75
76 /// Returns a mutable reference to the wrapped codec.
77 ///
78 /// The next value operation starts a fresh codec lifecycle, so mutations
79 /// are applied to the following operation.
80 #[inline(always)]
81 #[must_use]
82 pub fn codec_mut(&mut self) -> &mut C {
83 &mut self.codec
84 }
85
86 /// Consumes the adapter and returns its wrapped codec.
87 #[inline(always)]
88 #[must_use]
89 pub fn into_codec(self) -> C {
90 self.codec
91 }
92
93 /// Decodes exactly one encoded value from `input`.
94 ///
95 /// # Parameters
96 ///
97 /// - `input`: Encoded units for exactly one value.
98 ///
99 /// # Returns
100 ///
101 /// Returns the decoded value.
102 ///
103 /// Codecs that may emit decode reset or finish values must use
104 /// [`Self::decode_lifecycle`] or [`Self::decode_lifecycle_with_scratch`].
105 ///
106 /// # Errors
107 ///
108 /// Returns [`crate::TranscodeFailure::UnsupportedDecodeLifecycleOutput`]
109 /// before inspecting `input` or running codec hooks when reset or finish
110 /// may emit values. Returns
111 /// [`crate::TranscodeFailure::IncompleteInput`] when fewer than
112 /// [`Codec::MIN_UNITS_PER_VALUE`] units are available or when
113 /// [`crate::DecodeFailure::Incomplete`] is reported by the codec. In this
114 /// one-shot API, incomplete input is a terminal error rather than a
115 /// resumable streaming status. Returns a domain error when the wrapped
116 /// codec rejects or cannot finish the input. Returns
117 /// [`crate::TranscodeFailure::TrailingInput`] when a value is decoded but
118 /// extra input remains.
119 ///
120 /// # Panics
121 ///
122 /// Panics when the wrapped codec reports a consumed unit count larger than
123 /// the input slice length or [`Codec::MAX_DECODE_UNITS_PER_VALUE`].
124 pub fn decode(
125 &mut self,
126 input: &[C::Unit],
127 ) -> Result<C::Value, TranscodeDecodeErrorOf<C>> {
128 TranscodeFailure::ensure_no_decode_lifecycle_output::<C>()?;
129 let (value, reset_written, finish_written) =
130 decode_exact_complete_value(
131 &mut self.codec,
132 input,
133 &mut [],
134 &mut [],
135 )?;
136 debug_assert_eq!(0, reset_written);
137 debug_assert_eq!(0, finish_written);
138 Ok(value)
139 }
140
141 /// Decodes exactly one value and preserves all lifecycle output.
142 ///
143 /// # Parameters
144 ///
145 /// - `input`: Encoded units for exactly one value.
146 ///
147 /// # Returns
148 ///
149 /// Returns reset values, the main decoded value, and finish values in
150 /// separate owned buffers.
151 ///
152 /// # Errors
153 ///
154 /// Returns a framework error when input is incomplete or has trailing
155 /// units. Returns a phase-aware domain error when reset, decode, or finish
156 /// fails.
157 ///
158 /// # Panics
159 ///
160 /// Panics when the wrapped codec violates its declared reset, decode, or
161 /// finish bounds.
162 pub fn decode_lifecycle(
163 &mut self,
164 input: &[C::Unit],
165 ) -> Result<DecodeLifecycleOutput<C::Value>, TranscodeDecodeErrorOf<C>>
166 where
167 C::Value: Default,
168 {
169 let mut reset = Vec::new();
170 reset
171 .try_reserve(C::MAX_DECODE_RESET_VALUES)
172 .map_err(|_| TranscodeFailure::allocation_failed())?;
173 reset.resize_with(C::MAX_DECODE_RESET_VALUES, C::Value::default);
174 let mut finish = Vec::new();
175 finish
176 .try_reserve(C::MAX_DECODE_FINISH_VALUES)
177 .map_err(|_| TranscodeFailure::allocation_failed())?;
178 finish.resize_with(C::MAX_DECODE_FINISH_VALUES, C::Value::default);
179 let (value, reset_written, finish_written) = self
180 .decode_lifecycle_with_scratch(input, &mut reset, &mut finish)?
181 .into_parts();
182 reset.truncate(reset_written);
183 finish.truncate(finish_written);
184 Ok(DecodeLifecycleOutput::new(reset, value, finish))
185 }
186
187 /// Decodes exactly one value into separate lifecycle output buffers.
188 ///
189 /// # Parameters
190 ///
191 /// - `input`: Encoded units for exactly one value.
192 /// - `reset_output`: Destination for values emitted by decode reset.
193 /// - `finish_output`: Destination for values emitted by decode finish.
194 ///
195 /// # Returns
196 ///
197 /// Returns the main decoded value and the initialized lengths of both
198 /// lifecycle output buffers.
199 ///
200 /// # Errors
201 ///
202 /// Returns a framework error before running any lifecycle hook when either
203 /// output buffer is shorter than its corresponding codec bound. Also
204 /// returns incomplete-input, trailing-input, or phase-aware domain errors.
205 ///
206 /// # Panics
207 ///
208 /// Panics when the wrapped codec violates its declared reset, decode, or
209 /// finish bounds.
210 pub fn decode_lifecycle_with_scratch(
211 &mut self,
212 input: &[C::Unit],
213 reset_output: &mut [C::Value],
214 finish_output: &mut [C::Value],
215 ) -> Result<DecodeLifecycleProgress<C::Value>, TranscodeDecodeErrorOf<C>>
216 {
217 let (value, reset_written, finish_written) =
218 decode_exact_complete_value(
219 &mut self.codec,
220 input,
221 reset_output,
222 finish_output,
223 )?;
224 Ok(DecodeLifecycleProgress::new(
225 value,
226 reset_written,
227 finish_written,
228 ))
229 }
230}
231
232impl<C> ValueDecoder<[C::Unit]> for CodecValueDecoder<C>
233where
234 C: Codec,
235{
236 type Output = C::Value;
237 type Error = TranscodeDecodeErrorOf<C>;
238
239 #[inline(always)]
240 fn decode(
241 &mut self,
242 input: &[C::Unit],
243 ) -> Result<Self::Output, Self::Error> {
244 self.decode(input)
245 }
246}
247
248impl<C> fmt::Debug for CodecValueDecoder<C>
249where
250 C: Codec + fmt::Debug,
251{
252 /// Formats the decoder without requiring finished values to be printable.
253 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
254 formatter
255 .debug_struct("CodecValueDecoder")
256 .field("codec", &self.codec)
257 .finish()
258 }
259}
260
261impl<C> Default for CodecValueDecoder<C>
262where
263 C: Codec + Default,
264{
265 /// Creates a decoder from the default codec.
266 #[inline(always)]
267 fn default() -> Self {
268 Self::new(C::default())
269 }
270}