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}