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 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}