Skip to main content

qubit_codec/value/
codec_value_decoder.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2026 Haixing Hu.
4 *
5 *    SPDX-License-Identifier: Apache-2.0
6 *
7 *    Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10//! Value decoder adapter backed by a low-level codec.
11
12use super::ValueDecoder;
13use crate::{
14    Codec,
15    CodecDecodeError,
16    codec::assert_unit_bounds,
17};
18
19/// Decodes one encoded unit slice into one owned value by using a [`Codec`].
20///
21/// `CodecValueDecoder` is the default bridge from the low-level unchecked
22/// [`Codec`] contract to the convenience-layer [`ValueDecoder`] contract. The
23/// supplied input slice must contain exactly one encoded value. Successfully
24/// decoded prefixes followed by extra units are reported as trailing input.
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> {
36    /// Creates a decoder backed by `codec`.
37    ///
38    /// # Parameters
39    ///
40    /// - `codec`: Low-level codec used to decode one value.
41    ///
42    /// # Returns
43    ///
44    /// Returns a value decoder adapter for the supplied codec.
45    #[must_use]
46    #[inline(always)]
47    pub const fn new(codec: C) -> Self {
48        Self { codec }
49    }
50}
51
52impl<C> ValueDecoder<[C::Unit]> for CodecValueDecoder<C>
53where
54    C: Codec,
55{
56    type Output = C::Value;
57    type Error = CodecDecodeError<C::DecodeError>;
58
59    /// Decodes exactly one encoded value from `input`.
60    ///
61    /// # Parameters
62    ///
63    /// - `input`: Encoded units for exactly one value.
64    ///
65    /// # Returns
66    ///
67    /// Returns the decoded value.
68    ///
69    /// # Errors
70    ///
71    /// Returns [`CodecDecodeError::Incomplete`] when fewer than
72    /// [`Codec::min_units_per_value`] units are available. Returns
73    /// [`CodecDecodeError::Decode`] when the wrapped codec rejects the input.
74    /// Returns [`CodecDecodeError::TrailingInput`] when a value is decoded but
75    /// extra input remains.
76    ///
77    /// # Panics
78    ///
79    /// Panics when the wrapped codec reports a consumed unit count larger than
80    /// the input slice length.
81    fn decode(&self, input: &[C::Unit]) -> Result<Self::Output, Self::Error> {
82        assert_unit_bounds::<C>(&self.codec);
83        let min_units = self.codec.min_units_per_value().get();
84        if input.len() < min_units {
85            return Err(CodecDecodeError::incomplete(0, min_units, input.len()));
86        }
87
88        // SAFETY: The input slice has at least the codec's declared minimum
89        // number of readable units from index zero.
90        let (value, consumed) =
91            unsafe { self.codec.decode_unchecked(input, 0) }.map_err(|error| CodecDecodeError::decode(error, 0))?;
92        let consumed = consumed.get();
93        assert!(
94            consumed <= input.len(),
95            "Codec::decode_unchecked consumed beyond available input",
96        );
97
98        let remaining = input.len() - consumed;
99        if remaining == 0 {
100            Ok(value)
101        } else {
102            Err(CodecDecodeError::trailing_input(consumed, remaining))
103        }
104    }
105}