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