Skip to main content

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
156    /// [`crate::DecodeFailure::Incomplete`] is reported by the codec. In this
157    /// one-shot API, incomplete input is a terminal error rather than a
158    /// resumable streaming status. Returns a domain error when the wrapped
159    /// codec rejects or cannot finish the input. Returns
160    /// [`crate::TranscodeFailure::TrailingInput`] when a value is decoded but
161    /// extra input remains.
162    ///
163    /// # Panics
164    ///
165    /// Panics when the wrapped codec reports a consumed unit count larger than
166    /// the input slice length or [`Codec::MAX_DECODE_UNITS_PER_VALUE`].
167    pub fn decode(&mut self, input: &[C::Unit]) -> Result<C::Value, TranscodeDecodeErrorOf<C>> {
168        TranscodeFailure::ensure_no_decode_lifecycle_output::<C>()?;
169        let (value, reset_written, finish_written) =
170            decode_exact_complete_value(&mut self.codec, input, &mut [], &mut [])?;
171        debug_assert_eq!(0, reset_written);
172        debug_assert_eq!(0, finish_written);
173        Ok(value)
174    }
175
176    /// Decodes exactly one value and preserves all lifecycle output.
177    ///
178    /// # Parameters
179    ///
180    /// - `input`: Encoded units for exactly one value.
181    ///
182    /// # Returns
183    ///
184    /// Returns reset values, the main decoded value, and finish values in
185    /// separate owned buffers.
186    ///
187    /// # Errors
188    ///
189    /// Returns a framework error when input is incomplete or has trailing
190    /// units. Returns a phase-aware domain error when reset, decode, or finish
191    /// fails. Returns an allocation failure when either lifecycle buffer cannot
192    /// reserve its declared capacity.
193    ///
194    /// # Panics
195    ///
196    /// Panics when the wrapped codec violates its declared reset, decode, or
197    /// finish bounds.
198    pub fn decode_lifecycle(
199        &mut self,
200        input: &[C::Unit],
201    ) -> Result<DecodeLifecycleOutput<C::Value>, TranscodeDecodeErrorOf<C>>
202    where
203        C::Value: Default,
204    {
205        let mut reset = Vec::new();
206        try_reserve_vec(&mut reset, C::MAX_DECODE_RESET_VALUES).map_err(|_| TranscodeFailure::allocation_failed())?;
207        reset.resize_with(C::MAX_DECODE_RESET_VALUES, C::Value::default);
208        let mut finish = Vec::new();
209        try_reserve_vec(&mut finish, C::MAX_DECODE_FINISH_VALUES).map_err(|_| TranscodeFailure::allocation_failed())?;
210        finish.resize_with(C::MAX_DECODE_FINISH_VALUES, C::Value::default);
211        let (value, reset_written, finish_written) = self
212            .decode_lifecycle_with_scratch(input, &mut reset, &mut finish)?
213            .into_parts();
214        reset.truncate(reset_written);
215        finish.truncate(finish_written);
216        Ok(DecodeLifecycleOutput::new(reset, value, finish))
217    }
218
219    /// Decodes exactly one value into separate lifecycle output buffers.
220    ///
221    /// # Parameters
222    ///
223    /// - `input`: Encoded units for exactly one value.
224    /// - `reset_output`: Destination for values emitted by decode reset.
225    /// - `finish_output`: Destination for values emitted by decode finish.
226    ///
227    /// # Returns
228    ///
229    /// Returns the main decoded value and the initialized lengths of both
230    /// lifecycle output buffers.
231    ///
232    /// # Errors
233    ///
234    /// Returns a framework error before running any lifecycle hook when either
235    /// output buffer is shorter than its corresponding codec bound. Also
236    /// returns incomplete-input, trailing-input, or phase-aware domain errors.
237    ///
238    /// # Panics
239    ///
240    /// Panics when the wrapped codec violates its declared reset, decode, or
241    /// finish bounds.
242    pub fn decode_lifecycle_with_scratch(
243        &mut self,
244        input: &[C::Unit],
245        reset_output: &mut [C::Value],
246        finish_output: &mut [C::Value],
247    ) -> Result<DecodeLifecycleProgress<C::Value>, TranscodeDecodeErrorOf<C>> {
248        let (value, reset_written, finish_written) =
249            decode_exact_complete_value(&mut self.codec, input, reset_output, finish_output)?;
250        Ok(DecodeLifecycleProgress::new(value, reset_written, finish_written))
251    }
252}
253
254impl<C> ValueDecoder<[C::Unit]> for CodecValueDecoder<C>
255where
256    C: Codec,
257{
258    /// Owned value returned after the complete decode lifecycle.
259    type Output = C::Value;
260    /// Framework or phase-aware codec failure from one-value decoding.
261    type Error = TranscodeDecodeErrorOf<C>;
262
263    /// Decodes one value through the owned-value adapter.
264    ///
265    /// # Parameters
266    ///
267    /// - `input`: Complete encoded representation of exactly one value.
268    ///
269    /// # Returns
270    ///
271    /// The owned decoded value after finishing the codec lifecycle.
272    ///
273    /// # Errors
274    ///
275    /// Returns the same unsupported-lifecycle, incomplete-input,
276    /// trailing-input, and codec errors as [`Self::decode`].
277    ///
278    /// # Panics
279    ///
280    /// Panics if the codec reports consumption beyond its bounds or the input.
281    fn decode(&mut self, input: &[C::Unit]) -> Result<Self::Output, Self::Error> {
282        self.decode(input)
283    }
284}
285
286impl<C> fmt::Debug for CodecValueDecoder<C>
287where
288    C: Codec + fmt::Debug,
289{
290    /// Formats the decoder without requiring finished values to be printable.
291    ///
292    /// # Parameters
293    ///
294    /// - `formatter`: Destination and formatting options.
295    ///
296    /// # Returns
297    ///
298    /// Unit on successful formatting.
299    ///
300    /// # Errors
301    ///
302    /// Returns the formatter error if writing the codec representation fails.
303    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
304        formatter
305            .debug_struct("CodecValueDecoder")
306            .field("codec", &self.codec)
307            .finish()
308    }
309}
310
311impl<C> Default for CodecValueDecoder<C>
312where
313    C: Codec + Default,
314{
315    /// Creates a decoder from the default codec.
316    ///
317    /// # Returns
318    ///
319    /// An adapter owning `C::default()`.
320    ///
321    /// # Panics
322    ///
323    /// Fails at compile time for invalid codec decode bounds, as [`Self::new`].
324    /// May panic if the codec's own default constructor panics.
325    fn default() -> Self {
326        Self::new(C::default())
327    }
328}