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 core::fmt;
11
12use qubit_utils::try_reserve_vec;
13
14use super::ValueEncoder;
15use crate::CapacityError;
16use crate::Codec;
17use crate::TranscodeEncodeErrorOf;
18use crate::TranscodeFailure;
19use crate::codec::assert_unit_bounds;
20use crate::value::codec_value_lifecycle::encode_complete_value_into_reserved;
21use crate::value::codec_value_lifecycle::max_complete_encode_units;
22
23/// Encodes one borrowed value into owned units by using a [`Codec`].
24///
25/// `CodecValueEncoder` is the default bridge from the low-level unchecked
26/// [`Codec`] contract to the convenience-layer [`ValueEncoder`] contract. Each
27/// call emits stream-start output through [`Codec::encode_reset`], encodes one
28/// value through [`Codec::encode`], finishes encode-side state through
29/// [`Codec::encode_finish`], and returns the owned output truncated to the
30/// units actually written.
31///
32/// # Type Parameters
33///
34/// - `C`: Low-level codec used to encode one value.
35pub struct CodecValueEncoder<C> {
36    /// Low-level codec used for one-value encoding.
37    codec: C,
38}
39
40impl<C> CodecValueEncoder<C>
41where
42    C: Codec,
43{
44    /// Creates an encoder backed by `codec`.
45    ///
46    /// # Parameters
47    ///
48    /// - `codec`: Low-level codec used to encode one value.
49    ///
50    /// # Returns
51    ///
52    /// Returns a value encoder adapter for the supplied codec.
53    ///
54    /// # Compile-Time Checks
55    ///
56    /// Fails to compile when the supplied codec declares a zero decode unit
57    /// bound or when [`Codec::MIN_UNITS_PER_VALUE`] exceeds
58    /// [`Codec::MAX_DECODE_UNITS_PER_VALUE`]. The encode bound may be zero for
59    /// a fully buffered codec.
60    #[inline]
61    #[must_use]
62    pub fn new(codec: C) -> Self {
63        assert_unit_bounds::<C>();
64        Self { codec }
65    }
66
67    /// Returns a shared reference to the wrapped codec.
68    #[inline(always)]
69    #[must_use]
70    pub const fn codec(&self) -> &C {
71        &self.codec
72    }
73
74    /// Returns a mutable reference to the wrapped codec.
75    ///
76    /// The next value operation starts a fresh codec lifecycle, so mutations
77    /// are applied to the following operation.
78    #[inline(always)]
79    #[must_use]
80    pub fn codec_mut(&mut self) -> &mut C {
81        &mut self.codec
82    }
83
84    /// Consumes the adapter and returns its wrapped codec.
85    #[inline(always)]
86    #[must_use]
87    pub fn into_codec(self) -> C {
88        self.codec
89    }
90
91    /// Encodes one borrowed value and appends the emitted units to `output`.
92    ///
93    /// This method is the reusable-buffer counterpart of
94    /// [`ValueEncoder::encode`]. It emits stream-start output through
95    /// [`Codec::encode_reset`], encodes `input` through [`Codec::encode`], and
96    /// finishes encode-side state through [`Codec::encode_finish`], appending
97    /// only the units actually written. When encoding fails, the vector length
98    /// is restored to its original value.
99    ///
100    /// # Parameters
101    ///
102    /// - `input`: Value to encode.
103    /// - `output`: Destination vector receiving appended encoded units.
104    ///
105    /// # Returns
106    ///
107    /// Returns the number of units appended to `output`.
108    ///
109    /// # Errors
110    ///
111    /// Returns the wrapped codec's encode error when reset output, `input`, or
112    /// finish output cannot be represented. Returns a framework error when
113    /// output length arithmetic overflows.
114    ///
115    /// # Panics
116    ///
117    /// Panics when the wrapped codec reports more reset or finish output than
118    /// its declared bounds, when [`Codec::encode_len`] exceeds
119    /// [`Codec::MAX_ENCODE_UNITS_PER_VALUE`], or when encoding writes a
120    /// different value width than [`Codec::encode_len`].
121    pub fn encode_into(
122        &mut self,
123        input: &C::Value,
124        output: &mut Vec<C::Unit>,
125    ) -> Result<usize, TranscodeEncodeErrorOf<C>>
126    where
127        C::Unit: Default,
128    {
129        let units = max_complete_encode_units::<C>()?;
130        let original_len = output.len();
131        let target_len = original_len
132            .checked_add(units)
133            .ok_or(CapacityError::OutputLengthOverflow)?;
134        try_reserve_vec(output, units).map_err(|_| TranscodeFailure::allocation_failed())?;
135        output.resize_with(target_len, C::Unit::default);
136
137        match encode_complete_value_into_reserved(&mut self.codec, input, output, original_len, units) {
138            Ok(written) => {
139                output.truncate(original_len + written);
140                Ok(written)
141            }
142            Err(error) => {
143                output.truncate(original_len);
144                Err(error)
145            }
146        }
147    }
148}
149
150impl<C> ValueEncoder<C::Value> for CodecValueEncoder<C>
151where
152    C: Codec,
153    C::Unit: Default,
154{
155    type Output = Vec<C::Unit>;
156    type Error = TranscodeEncodeErrorOf<C>;
157
158    /// Encodes one borrowed value into owned units.
159    ///
160    /// # Parameters
161    ///
162    /// - `input`: Value to encode.
163    ///
164    /// # Returns
165    ///
166    /// Returns stream-start output followed by the units written for `input`
167    /// and any encode-finish output.
168    ///
169    /// # Errors
170    ///
171    /// Returns the wrapped codec's encode error when reset output, `input`, or
172    /// finish output cannot be represented.
173    ///
174    /// # Panics
175    ///
176    /// Panics when the wrapped codec reports more reset or finish output than
177    /// its declared bounds, or a value width different from
178    /// [`Codec::encode_len`].
179    fn encode(&mut self, input: &C::Value) -> Result<Self::Output, Self::Error> {
180        let mut output = Vec::new();
181        self.encode_into(input, &mut output)?;
182        Ok(output)
183    }
184}
185
186impl<C> fmt::Debug for CodecValueEncoder<C>
187where
188    C: Codec + fmt::Debug,
189{
190    /// Formats the encoder without requiring finished values to be printable.
191    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
192        formatter
193            .debug_struct("CodecValueEncoder")
194            .field("codec", &self.codec)
195            .finish()
196    }
197}
198
199impl<C> Default for CodecValueEncoder<C>
200where
201    C: Codec + Default,
202{
203    /// Creates an encoder from the default codec.
204    #[inline(always)]
205    fn default() -> Self {
206        Self::new(C::default())
207    }
208}