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    TranscodeError,
16    codec::assert_unit_bounds,
17};
18
19/// Encodes one borrowed value into owned units by using a [`Codec`].
20///
21/// `CodecValueEncoder` is the default bridge from the low-level unchecked
22/// [`Codec`] contract to the convenience-layer [`ValueEncoder`] contract. Each
23/// call emits stream-start output through [`Codec::encode_reset`], then encodes
24/// one value through [`Codec::encode`], and returns the owned output truncated
25/// to the units actually written.
26///
27/// # Type Parameters
28///
29/// - `C`: Low-level codec used to encode one value.
30#[derive(Debug, Default)]
31pub struct CodecValueEncoder<C> {
32    /// Low-level codec used for one-value encoding.
33    codec: C,
34}
35
36impl<C> CodecValueEncoder<C>
37where
38    C: Codec,
39{
40    /// Creates an encoder backed by `codec`.
41    ///
42    /// # Parameters
43    ///
44    /// - `codec`: Low-level codec used to encode one value.
45    ///
46    /// # Returns
47    ///
48    /// Returns a value encoder adapter for the supplied codec.
49    ///
50    /// # Panics
51    ///
52    /// In debug builds, panics when the supplied codec violates the
53    /// [`Codec::MIN_UNITS_PER_VALUE`] / [`Codec::MAX_UNITS_PER_VALUE`] ordering
54    /// invariant. Release builds skip this check because the invariant is the
55    /// responsibility of the [`Codec`] implementation.
56    #[inline]
57    #[must_use]
58    pub fn new(codec: C) -> Self {
59        assert_unit_bounds::<C>();
60        Self { codec }
61    }
62}
63
64impl<C> ValueEncoder<C::Value> for CodecValueEncoder<C>
65where
66    C: Codec,
67    C::Unit: Default,
68{
69    type Output = Vec<C::Unit>;
70    type Error = TranscodeError<CodecEncodeError<C::EncodeError>>;
71
72    /// Encodes one borrowed value into owned units.
73    ///
74    /// # Parameters
75    ///
76    /// - `input`: Value to encode.
77    ///
78    /// # Returns
79    ///
80    /// Returns stream-start output followed by the units written for `input`.
81    ///
82    /// # Errors
83    ///
84    /// Returns the wrapped codec's encode error when reset output or `input`
85    /// cannot be represented.
86    ///
87    /// # Panics
88    ///
89    /// Panics when the wrapped codec reports more reset output than
90    /// [`Codec::MAX_ENCODE_RESET_UNITS`] or a value width different from
91    /// [`Codec::encode_len`].
92    fn encode(
93        &mut self,
94        input: &C::Value,
95    ) -> Result<Self::Output, Self::Error> {
96        if !self.codec.can_encode_value(input) {
97            return Err(TranscodeError::domain(
98                CodecEncodeError::unencodable_value(0),
99            ));
100        }
101        let units = C::MAX_ENCODE_RESET_UNITS
102            .checked_add(self.codec.encode_len(input).get())
103            .ok_or_else(TranscodeError::output_length_overflow)?;
104        let mut output = Vec::with_capacity(units);
105        output.resize_with(units, C::Unit::default);
106        let written =
107            self.codec.encode_value_with_reset(input, &mut output, 0)?;
108        output.truncate(written);
109        Ok(output)
110    }
111}