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 super::ValueDecoder;
11use crate::{
12    Codec,
13    CodecDecodeError,
14    CodecValueExt,
15    codec::assert_unit_bounds,
16};
17
18/// Decodes one encoded unit slice into one owned value by using a [`Codec`].
19///
20/// `CodecValueDecoder` is the default bridge from the low-level unchecked
21/// [`Codec`] contract to the convenience-layer [`ValueDecoder`] contract. The
22/// supplied input slice must contain exactly one encoded value. After a
23/// successful decode, the adapter calls [`Codec::decode_flush`] to reset
24/// decode-side stream state for the next call.
25///
26/// # Type Parameters
27///
28/// - `C`: Low-level codec used to decode one value.
29#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
30pub struct CodecValueDecoder<C> {
31    /// Low-level codec used for one-value decoding.
32    codec: C,
33}
34
35impl<C> CodecValueDecoder<C>
36where
37    C: Codec,
38{
39    /// Creates a decoder backed by `codec`.
40    ///
41    /// # Parameters
42    ///
43    /// - `codec`: Low-level codec used to decode one value.
44    ///
45    /// # Returns
46    ///
47    /// Returns a value decoder adapter for the supplied codec.
48    ///
49    /// # Panics
50    ///
51    /// Panics when the supplied codec violates the
52    /// [`Codec::min_units_per_value`] / [`Codec::max_units_per_value`] ordering
53    /// invariant. Validating once at construction lets the hot decode path
54    /// skip the check.
55    #[must_use]
56    #[inline]
57    pub fn new(codec: C) -> Self {
58        assert_unit_bounds::<C>(&codec);
59        Self { codec }
60    }
61}
62
63impl<C> ValueDecoder<[C::Unit]> for CodecValueDecoder<C>
64where
65    C: Codec,
66{
67    type Output = C::Value;
68    type Error = CodecDecodeError<C::DecodeError>;
69
70    /// Decodes exactly one encoded value from `input`.
71    ///
72    /// # Parameters
73    ///
74    /// - `input`: Encoded units for exactly one value.
75    ///
76    /// # Returns
77    ///
78    /// Returns the decoded value.
79    ///
80    /// # Errors
81    ///
82    /// Returns [`CodecDecodeError::Incomplete`] when fewer than
83    /// [`Codec::min_units_per_value`] units are available. Returns
84    /// [`CodecDecodeError::Decode`] when the wrapped codec rejects the input.
85    /// Returns [`CodecDecodeError::TrailingInput`] when a value is decoded but
86    /// extra input remains.
87    ///
88    /// # Panics
89    ///
90    /// Panics when the wrapped codec reports a consumed unit count larger than
91    /// the input slice length, or when flush output exceeds
92    /// [`Codec::max_decode_flush_values`].
93    fn decode(
94        &mut self,
95        input: &[C::Unit],
96    ) -> Result<Self::Output, Self::Error> {
97        let flush_cap = self.codec.max_decode_flush_values();
98        let (value, _) = if flush_cap == 0 {
99            self.codec
100                .decode_exact_value_with_flush(input, &mut [], 0)?
101        } else {
102            let mut scratch = Vec::with_capacity(flush_cap);
103            scratch.resize_with(flush_cap, C::Value::default);
104            self.codec
105                .decode_exact_value_with_flush(input, &mut scratch, 0)?
106        };
107
108        Ok(value)
109    }
110}