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}