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}