Skip to main content

qubit_codec/value/
codec_value_encoder.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 encoder adapter backed by a low-level codec.
9
10use super::ValueEncoder;
11use crate::{
12    Codec,
13    CodecEncodeError,
14    CodecValueExt,
15    codec::assert_unit_bounds,
16};
17
18/// Encodes one borrowed value into owned units by using a [`Codec`].
19///
20/// `CodecValueEncoder` is the default bridge from the low-level unchecked
21/// [`Codec`] contract to the convenience-layer [`ValueEncoder`] contract. Each
22/// call emits stream-start output through [`Codec::encode_reset`], then encodes
23/// one value through [`Codec::encode`], and returns the owned output truncated
24/// to the units actually written.
25///
26/// # Type Parameters
27///
28/// - `C`: Low-level codec used to encode one value.
29#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
30pub struct CodecValueEncoder<C> {
31    /// Low-level codec used for one-value encoding.
32    codec: C,
33}
34
35impl<C> CodecValueEncoder<C>
36where
37    C: Codec,
38{
39    /// Creates an encoder backed by `codec`.
40    ///
41    /// # Parameters
42    ///
43    /// - `codec`: Low-level codec used to encode one value.
44    ///
45    /// # Returns
46    ///
47    /// Returns a value encoder 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 encode 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> ValueEncoder<C::Value> for CodecValueEncoder<C>
64where
65    C: Codec,
66{
67    type Output = Vec<C::Unit>;
68    type Error = CodecEncodeError<C::EncodeError>;
69
70    /// Encodes one borrowed value into owned units.
71    ///
72    /// # Parameters
73    ///
74    /// - `input`: Value to encode.
75    ///
76    /// # Returns
77    ///
78    /// Returns stream-start output followed by the units written for `input`.
79    ///
80    /// # Errors
81    ///
82    /// Returns the wrapped codec's encode error when reset output or `input`
83    /// cannot be represented.
84    ///
85    /// # Panics
86    ///
87    /// Panics when the wrapped codec reports more reset output than
88    /// [`Codec::max_encode_reset_units`] or a value width different from
89    /// [`Codec::encode_len`].
90    fn encode(
91        &mut self,
92        input: &C::Value,
93    ) -> Result<Self::Output, Self::Error> {
94        if !self.codec.can_encode_value(input) {
95            return Err(CodecEncodeError::unencodable_value(0));
96        }
97        let units = self
98            .codec
99            .max_encode_reset_units()
100            .checked_add(self.codec.encode_len(input).get())
101            .ok_or_else(CodecEncodeError::output_length_overflow)?;
102        let mut output = vec![C::Unit::default(); units];
103        let written =
104            self.codec.encode_value_with_reset(input, &mut output, 0)?;
105        output.truncate(written);
106        Ok(output)
107    }
108}