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