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}