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 qubit_utils::try_reserve_vec;
13
14use super::DecodeLifecycleOutput;
15use super::DecodeLifecycleProgress;
16use super::ValueDecoder;
17use crate::Codec;
18use crate::TranscodeDecodeErrorOf;
19use crate::TranscodeFailure;
20use crate::codec::assert_unit_bounds;
21use crate::value::codec_value_lifecycle::decode_exact_complete_value;
22
23/// Decodes one encoded unit slice into one owned value by using a [`Codec`].
24///
25/// `CodecValueDecoder` is the default bridge from the low-level unchecked
26/// [`Codec`] contract to the convenience-layer [`ValueDecoder`] contract. The
27/// supplied input slice must contain exactly one encoded value. The adapter
28/// runs the complete decode lifecycle, including [`Codec::decode_finish`],
29/// before returning the decoded value.
30///
31/// # Type Parameters
32///
33/// - `C`: Low-level codec used to decode one value.
34///
35/// # Examples
36///
37/// ```
38/// use std::convert::Infallible;
39/// use std::num::NonZeroUsize;
40///
41/// use qubit_codec::Codec;
42/// use qubit_codec::CodecValueDecoder;
43/// use qubit_codec::DecodeFailure;
44///
45/// struct Identity;
46/// impl Codec for Identity {
47/// type Value = u8;
48/// type Unit = u8;
49/// type DecodeError = Infallible;
50/// type EncodeError = Infallible;
51/// const MIN_UNITS_PER_VALUE: usize = 1;
52/// const MAX_DECODE_UNITS_PER_VALUE: usize = 1;
53/// const MAX_ENCODE_UNITS_PER_VALUE: usize = 1;
54/// unsafe fn decode(&mut self, input: &[u8], index: usize)
55/// -> Result<(u8, NonZeroUsize), DecodeFailure<Infallible>> {
56/// Ok((input[index], NonZeroUsize::new(1).unwrap()))
57/// }
58/// unsafe fn encode(&mut self, value: &u8, output: &mut [u8], index: usize)
59/// -> Result<usize, Infallible> {
60/// output[index] = *value;
61/// Ok(1)
62/// }
63/// }
64/// let mut decoder = CodecValueDecoder::new(Identity);
65/// assert_eq!(decoder.decode(&[7]).unwrap(), 7);
66/// ```
67pub struct CodecValueDecoder<C>
68where
69 C: Codec,
70{
71 /// Low-level codec used for one-value decoding.
72 codec: C,
73}
74
75impl<C> CodecValueDecoder<C>
76where
77 C: Codec,
78{
79 /// Creates a decoder backed by `codec`.
80 ///
81 /// # Parameters
82 ///
83 /// - `codec`: Low-level codec used to decode one value.
84 ///
85 /// # Returns
86 ///
87 /// Returns a value decoder adapter for the supplied codec.
88 ///
89 /// # Panics
90 ///
91 /// Fails at compile time if codec decode bounds are zero or the minimum
92 /// exceeds the maximum.
93 #[inline]
94 #[must_use]
95 pub fn new(codec: C) -> Self {
96 assert_unit_bounds::<C>();
97 Self { codec }
98 }
99
100 /// Returns a shared reference to the wrapped codec.
101 ///
102 /// # Returns
103 ///
104 /// The codec borrowed for as long as the adapter is borrowed.
105 #[inline]
106 #[must_use]
107 pub const fn codec(&self) -> &C {
108 &self.codec
109 }
110
111 /// Returns a mutable reference to the wrapped codec.
112 ///
113 /// The next value operation starts a fresh codec lifecycle, so mutations
114 /// are applied to the following operation.
115 ///
116 /// # Returns
117 ///
118 /// An exclusive borrow of the codec without allocating.
119 #[inline]
120 #[must_use]
121 pub fn codec_mut(&mut self) -> &mut C {
122 &mut self.codec
123 }
124
125 /// Consumes the adapter and returns its wrapped codec.
126 ///
127 /// # Returns
128 ///
129 /// The owned codec, preserving its most recent lifecycle state.
130 #[inline]
131 #[must_use]
132 pub fn into_codec(self) -> C {
133 self.codec
134 }
135
136 /// Decodes exactly one encoded value from `input`.
137 ///
138 /// # Parameters
139 ///
140 /// - `input`: Encoded units for exactly one value.
141 ///
142 /// # Returns
143 ///
144 /// Returns the decoded value.
145 ///
146 /// Codecs that may emit decode reset or finish values must use
147 /// [`Self::decode_lifecycle`] or [`Self::decode_lifecycle_with_scratch`].
148 ///
149 /// # Errors
150 ///
151 /// Returns [`crate::TranscodeFailure::UnsupportedDecodeLifecycleOutput`]
152 /// before inspecting `input` or running codec hooks when reset or finish
153 /// may emit values. Returns
154 /// [`crate::TranscodeFailure::IncompleteInput`] when fewer than
155 /// [`Codec::MIN_UNITS_PER_VALUE`] units are available or when the codec
156 /// reports [`crate::DecodeFailure::Incomplete`] without a source.
157 /// An incomplete failure carrying a codec source is preserved as
158 /// [`crate::TranscodeDecodeError::Domain`] with
159 /// [`crate::TranscodeDomainError::Main`] phase information.
160 /// In this one-shot API, either form of incomplete input is a terminal
161 /// error rather than a resumable streaming status. Returns a domain error
162 /// when the wrapped codec rejects or cannot finish the input. Returns
163 /// [`crate::TranscodeFailure::TrailingInput`] when a value is decoded but
164 /// extra input remains.
165 ///
166 /// # Panics
167 ///
168 /// Panics when the wrapped codec reports a consumed unit count larger than
169 /// the input slice length or [`Codec::MAX_DECODE_UNITS_PER_VALUE`].
170 pub fn decode(&mut self, input: &[C::Unit]) -> Result<C::Value, TranscodeDecodeErrorOf<C>> {
171 TranscodeFailure::ensure_no_decode_lifecycle_output::<C>()?;
172 let (value, reset_written, finish_written) =
173 decode_exact_complete_value(&mut self.codec, input, &mut [], &mut [])?;
174 debug_assert_eq!(0, reset_written);
175 debug_assert_eq!(0, finish_written);
176 Ok(value)
177 }
178
179 /// Decodes exactly one value and preserves all lifecycle output.
180 ///
181 /// # Parameters
182 ///
183 /// - `input`: Encoded units for exactly one value.
184 ///
185 /// # Returns
186 ///
187 /// Returns reset values, the main decoded value, and finish values in
188 /// separate owned buffers.
189 ///
190 /// # Errors
191 ///
192 /// Returns a framework error for input shorter than the codec minimum,
193 /// incomplete input without a codec source, or trailing units. Incomplete
194 /// input carrying a codec source is preserved as a main-phase domain
195 /// error. Returns a phase-aware domain error when reset, decode, or finish
196 /// fails. Returns an allocation failure when either lifecycle buffer cannot
197 /// reserve its declared capacity.
198 ///
199 /// # Panics
200 ///
201 /// Panics when the wrapped codec violates its declared reset, decode, or
202 /// finish bounds.
203 pub fn decode_lifecycle(
204 &mut self,
205 input: &[C::Unit],
206 ) -> Result<DecodeLifecycleOutput<C::Value>, TranscodeDecodeErrorOf<C>>
207 where
208 C::Value: Default,
209 {
210 let mut reset = Vec::new();
211 try_reserve_vec(&mut reset, C::MAX_DECODE_RESET_VALUES).map_err(|_| TranscodeFailure::allocation_failed())?;
212 reset.resize_with(C::MAX_DECODE_RESET_VALUES, C::Value::default);
213 let mut finish = Vec::new();
214 try_reserve_vec(&mut finish, C::MAX_DECODE_FINISH_VALUES).map_err(|_| TranscodeFailure::allocation_failed())?;
215 finish.resize_with(C::MAX_DECODE_FINISH_VALUES, C::Value::default);
216 let (value, reset_written, finish_written) = self
217 .decode_lifecycle_with_scratch(input, &mut reset, &mut finish)?
218 .into_parts();
219 reset.truncate(reset_written);
220 finish.truncate(finish_written);
221 Ok(DecodeLifecycleOutput::new(reset, value, finish))
222 }
223
224 /// Decodes exactly one value into separate lifecycle output buffers.
225 ///
226 /// # Parameters
227 ///
228 /// - `input`: Encoded units for exactly one value.
229 /// - `reset_output`: Destination for values emitted by decode reset.
230 /// - `finish_output`: Destination for values emitted by decode finish.
231 ///
232 /// # Returns
233 ///
234 /// Returns the main decoded value and the initialized lengths of both
235 /// lifecycle output buffers.
236 ///
237 /// # Errors
238 ///
239 /// Returns a framework error before running any lifecycle hook when either
240 /// output buffer is shorter than its corresponding codec bound. Also
241 /// returns a framework error for input shorter than the codec minimum,
242 /// incomplete input without a codec source, or trailing units. Incomplete
243 /// input carrying a codec source is preserved as a main-phase domain
244 /// error. Returns phase-aware domain errors when reset, decode, or finish
245 /// fails.
246 ///
247 /// Both output capacities are checked before any hook runs, so insufficient
248 /// capacity leaves codec state and scratch unchanged. After lifecycle
249 /// execution starts, an error may leave codec state and either output
250 /// buffer changed; these changes are not rolled back. An error provides no
251 /// usable reset or finish output lengths. Consume output prefixes only
252 /// using lengths from a successful result, and retry after failure only
253 /// when the concrete codec defines a recovery protocol.
254 ///
255 /// # Panics
256 ///
257 /// Panics when the wrapped codec violates its declared reset, decode, or
258 /// finish bounds.
259 pub fn decode_lifecycle_with_scratch(
260 &mut self,
261 input: &[C::Unit],
262 reset_output: &mut [C::Value],
263 finish_output: &mut [C::Value],
264 ) -> Result<DecodeLifecycleProgress<C::Value>, TranscodeDecodeErrorOf<C>> {
265 let (value, reset_written, finish_written) =
266 decode_exact_complete_value(&mut self.codec, input, reset_output, finish_output)?;
267 Ok(DecodeLifecycleProgress::new(value, reset_written, finish_written))
268 }
269}
270
271impl<C> ValueDecoder<[C::Unit]> for CodecValueDecoder<C>
272where
273 C: Codec,
274{
275 /// Owned value returned after the complete decode lifecycle.
276 type Output = C::Value;
277 /// Framework or phase-aware codec failure from one-value decoding.
278 type Error = TranscodeDecodeErrorOf<C>;
279
280 /// Decodes one value through the owned-value adapter.
281 ///
282 /// # Parameters
283 ///
284 /// - `input`: Complete encoded representation of exactly one value.
285 ///
286 /// # Returns
287 ///
288 /// The owned decoded value after finishing the codec lifecycle.
289 ///
290 /// # Errors
291 ///
292 /// Returns the same unsupported-lifecycle, incomplete-input,
293 /// trailing-input, and codec errors as [`Self::decode`].
294 ///
295 /// # Panics
296 ///
297 /// Panics if the codec reports consumption beyond its bounds or the input.
298 #[inline]
299 fn decode(&mut self, input: &[C::Unit]) -> Result<Self::Output, Self::Error> {
300 self.decode(input)
301 }
302}
303
304impl<C> fmt::Debug for CodecValueDecoder<C>
305where
306 C: Codec + fmt::Debug,
307{
308 /// Formats the decoder without requiring finished values to be printable.
309 ///
310 /// # Parameters
311 ///
312 /// - `formatter`: Destination and formatting options.
313 ///
314 /// # Returns
315 ///
316 /// Unit on successful formatting.
317 ///
318 /// # Errors
319 ///
320 /// Returns the formatter error if writing the codec representation fails.
321 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
322 formatter
323 .debug_struct("CodecValueDecoder")
324 .field("codec", &self.codec)
325 .finish()
326 }
327}
328
329impl<C> Default for CodecValueDecoder<C>
330where
331 C: Codec + Default,
332{
333 /// Creates a decoder from the default codec.
334 ///
335 /// # Returns
336 ///
337 /// An adapter owning `C::default()`.
338 ///
339 /// # Panics
340 ///
341 /// Fails at compile time for invalid codec decode bounds, as [`Self::new`].
342 /// May panic if the codec's own default constructor panics.
343 fn default() -> Self {
344 Self::new(C::default())
345 }
346}