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