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 qubit_codec::{Codec, CodecValueDecoder};
39///
40/// fn make_decoder<C: Codec>(codec: C) -> CodecValueDecoder<C> {
41///     CodecValueDecoder::new(codec)
42/// }
43/// ```
44pub struct CodecValueDecoder<C>
45where
46    C: Codec,
47{
48    /// Low-level codec used for one-value decoding.
49    codec: C,
50}
51
52impl<C> CodecValueDecoder<C>
53where
54    C: Codec,
55{
56    /// Creates a decoder backed by `codec`.
57    ///
58    /// # Parameters
59    ///
60    /// - `codec`: Low-level codec used to decode one value.
61    ///
62    /// # Returns
63    ///
64    /// Returns a value decoder adapter for the supplied codec.
65    ///
66    /// # Panics
67    ///
68    /// Panics when the supplied codec declares invalid unit bounds or an
69    /// invalid decode unit bounds.
70    #[inline]
71    #[must_use]
72    pub fn new(codec: C) -> Self {
73        assert_unit_bounds::<C>();
74        Self { codec }
75    }
76
77    /// Returns a shared reference to the wrapped codec.
78    #[inline(always)]
79    #[must_use]
80    pub const fn codec(&self) -> &C {
81        &self.codec
82    }
83
84    /// Returns a mutable reference to the wrapped codec.
85    ///
86    /// The next value operation starts a fresh codec lifecycle, so mutations
87    /// are applied to the following operation.
88    #[inline(always)]
89    #[must_use]
90    pub fn codec_mut(&mut self) -> &mut C {
91        &mut self.codec
92    }
93
94    /// Consumes the adapter and returns its wrapped codec.
95    #[inline(always)]
96    #[must_use]
97    pub fn into_codec(self) -> C {
98        self.codec
99    }
100
101    /// Decodes exactly one encoded value from `input`.
102    ///
103    /// # Parameters
104    ///
105    /// - `input`: Encoded units for exactly one value.
106    ///
107    /// # Returns
108    ///
109    /// Returns the decoded value.
110    ///
111    /// Codecs that may emit decode reset or finish values must use
112    /// [`Self::decode_lifecycle`] or [`Self::decode_lifecycle_with_scratch`].
113    ///
114    /// # Errors
115    ///
116    /// Returns [`crate::TranscodeFailure::UnsupportedDecodeLifecycleOutput`]
117    /// before inspecting `input` or running codec hooks when reset or finish
118    /// may emit values. Returns
119    /// [`crate::TranscodeFailure::IncompleteInput`] when fewer than
120    /// [`Codec::MIN_UNITS_PER_VALUE`] units are available or when
121    /// [`crate::DecodeFailure::Incomplete`] is reported by the codec. In this
122    /// one-shot API, incomplete input is a terminal error rather than a
123    /// resumable streaming status. Returns a domain error when the wrapped
124    /// codec rejects or cannot finish the input. Returns
125    /// [`crate::TranscodeFailure::TrailingInput`] when a value is decoded but
126    /// extra input remains.
127    ///
128    /// # Panics
129    ///
130    /// Panics when the wrapped codec reports a consumed unit count larger than
131    /// the input slice length or [`Codec::MAX_DECODE_UNITS_PER_VALUE`].
132    pub fn decode(&mut self, input: &[C::Unit]) -> Result<C::Value, TranscodeDecodeErrorOf<C>> {
133        TranscodeFailure::ensure_no_decode_lifecycle_output::<C>()?;
134        let (value, reset_written, finish_written) =
135            decode_exact_complete_value(&mut self.codec, input, &mut [], &mut [])?;
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        try_reserve_vec(&mut reset, C::MAX_DECODE_RESET_VALUES).map_err(|_| TranscodeFailure::allocation_failed())?;
171        reset.resize_with(C::MAX_DECODE_RESET_VALUES, C::Value::default);
172        let mut finish = Vec::new();
173        try_reserve_vec(&mut finish, C::MAX_DECODE_FINISH_VALUES).map_err(|_| TranscodeFailure::allocation_failed())?;
174        finish.resize_with(C::MAX_DECODE_FINISH_VALUES, C::Value::default);
175        let (value, reset_written, finish_written) = self
176            .decode_lifecycle_with_scratch(input, &mut reset, &mut finish)?
177            .into_parts();
178        reset.truncate(reset_written);
179        finish.truncate(finish_written);
180        Ok(DecodeLifecycleOutput::new(reset, value, finish))
181    }
182
183    /// Decodes exactly one value into separate lifecycle output buffers.
184    ///
185    /// # Parameters
186    ///
187    /// - `input`: Encoded units for exactly one value.
188    /// - `reset_output`: Destination for values emitted by decode reset.
189    /// - `finish_output`: Destination for values emitted by decode finish.
190    ///
191    /// # Returns
192    ///
193    /// Returns the main decoded value and the initialized lengths of both
194    /// lifecycle output buffers.
195    ///
196    /// # Errors
197    ///
198    /// Returns a framework error before running any lifecycle hook when either
199    /// output buffer is shorter than its corresponding codec bound. Also
200    /// returns incomplete-input, trailing-input, or phase-aware domain errors.
201    ///
202    /// # Panics
203    ///
204    /// Panics when the wrapped codec violates its declared reset, decode, or
205    /// finish bounds.
206    pub fn decode_lifecycle_with_scratch(
207        &mut self,
208        input: &[C::Unit],
209        reset_output: &mut [C::Value],
210        finish_output: &mut [C::Value],
211    ) -> Result<DecodeLifecycleProgress<C::Value>, TranscodeDecodeErrorOf<C>> {
212        let (value, reset_written, finish_written) =
213            decode_exact_complete_value(&mut self.codec, input, reset_output, finish_output)?;
214        Ok(DecodeLifecycleProgress::new(value, reset_written, finish_written))
215    }
216}
217
218impl<C> ValueDecoder<[C::Unit]> for CodecValueDecoder<C>
219where
220    C: Codec,
221{
222    type Output = C::Value;
223    type Error = TranscodeDecodeErrorOf<C>;
224
225    /// Decodes one value through the owned-value adapter.
226    #[inline(always)]
227    fn decode(&mut self, input: &[C::Unit]) -> Result<Self::Output, Self::Error> {
228        self.decode(input)
229    }
230}
231
232impl<C> fmt::Debug for CodecValueDecoder<C>
233where
234    C: Codec + fmt::Debug,
235{
236    /// Formats the decoder without requiring finished values to be printable.
237    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
238        formatter
239            .debug_struct("CodecValueDecoder")
240            .field("codec", &self.codec)
241            .finish()
242    }
243}
244
245impl<C> Default for CodecValueDecoder<C>
246where
247    C: Codec + Default,
248{
249    /// Creates a decoder from the default codec.
250    #[inline(always)]
251    fn default() -> Self {
252        Self::new(C::default())
253    }
254}