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::ValueDecoder;
13use crate::{
14    Codec,
15    CodecDecodeError,
16    CodecValueExt,
17    TranscodeError,
18    codec::assert_unit_bounds,
19};
20
21/// Decodes one encoded unit slice into one owned value by using a [`Codec`].
22///
23/// `CodecValueDecoder` is the default bridge from the low-level unchecked
24/// [`Codec`] contract to the convenience-layer [`ValueDecoder`] contract. The
25/// supplied input slice must contain exactly one encoded value. After a
26/// successful decode, the adapter calls [`Codec::decode_flush`] to reset
27/// decode-side stream state for the next call.
28///
29/// # Type Parameters
30///
31/// - `C`: Low-level codec used to decode one value.
32pub struct CodecValueDecoder<C>
33where
34    C: Codec,
35{
36    /// Low-level codec used for one-value decoding.
37    codec: C,
38    /// Reusable storage for values emitted by `Codec::decode_flush`.
39    flush_scratch: Vec<C::Value>,
40}
41
42impl<C> fmt::Debug for CodecValueDecoder<C>
43where
44    C: Codec + fmt::Debug,
45{
46    /// Formats the decoder without requiring flushed values to be printable.
47    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
48        formatter
49            .debug_struct("CodecValueDecoder")
50            .field("codec", &self.codec)
51            .field("flush_scratch_len", &self.flush_scratch.len())
52            .field("flush_scratch_capacity", &self.flush_scratch.capacity())
53            .finish()
54    }
55}
56
57impl<C> Default for CodecValueDecoder<C>
58where
59    C: Codec + Default,
60{
61    /// Creates a decoder from the default codec.
62    #[inline(always)]
63    fn default() -> Self {
64        Self::new(C::default())
65    }
66}
67
68impl<C> CodecValueDecoder<C>
69where
70    C: Codec,
71{
72    /// Creates a decoder backed by `codec`.
73    ///
74    /// # Parameters
75    ///
76    /// - `codec`: Low-level codec used to decode one value.
77    ///
78    /// # Returns
79    ///
80    /// Returns a value decoder adapter for the supplied codec.
81    ///
82    /// # Panics
83    ///
84    /// In debug builds, panics when the supplied codec violates the
85    /// [`Codec::MIN_UNITS_PER_VALUE`] / [`Codec::MAX_UNITS_PER_VALUE`] ordering
86    /// invariant. Release builds skip this check because the invariant is the
87    /// responsibility of the [`Codec`] implementation.
88    #[inline]
89    #[must_use]
90    pub fn new(codec: C) -> Self {
91        assert_unit_bounds::<C>();
92        Self {
93            codec,
94            flush_scratch: Vec::new(),
95        }
96    }
97}
98
99impl<C> ValueDecoder<[C::Unit]> for CodecValueDecoder<C>
100where
101    C: Codec,
102    C::Value: Default,
103{
104    type Output = C::Value;
105    type Error = TranscodeError<CodecDecodeError<C::DecodeError>>;
106
107    /// Decodes exactly one encoded value from `input`.
108    ///
109    /// # Parameters
110    ///
111    /// - `input`: Encoded units for exactly one value.
112    ///
113    /// # Returns
114    ///
115    /// Returns the decoded value.
116    ///
117    /// # Errors
118    ///
119    /// Returns [`CodecDecodeError::Incomplete`] when fewer than
120    /// [`Codec::MIN_UNITS_PER_VALUE`] units are available. Returns
121    /// [`CodecDecodeError::Decode`] when the wrapped codec rejects the input.
122    /// Returns [`CodecDecodeError::TrailingInput`] when a value is decoded but
123    /// extra input remains.
124    ///
125    /// # Panics
126    ///
127    /// Panics when the wrapped codec reports a consumed unit count larger than
128    /// the input slice length, or when flush output exceeds
129    /// [`Codec::MAX_DECODE_FLUSH_VALUES`].
130    fn decode(
131        &mut self,
132        input: &[C::Unit],
133    ) -> Result<Self::Output, Self::Error> {
134        let flush_cap = C::MAX_DECODE_FLUSH_VALUES;
135        let (value, _) = if flush_cap == 0 {
136            self.codec
137                .decode_exact_value_with_flush(input, &mut [], 0)?
138        } else {
139            if self.flush_scratch.len() < flush_cap {
140                self.flush_scratch.resize_with(flush_cap, C::Value::default);
141            }
142            self.codec.decode_exact_value_with_flush(
143                input,
144                &mut self.flush_scratch,
145                0,
146            )?
147        };
148
149        Ok(value)
150    }
151}