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}