qubit_codec/transcode/adapter/codec_transcode_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//! Buffered encoder adapter backed by a low-level codec.
9
10use super::super::engine::TranscodeEncodeEngine;
11use super::CodecTranscodeEncodeHooks;
12use crate::{
13 CapacityError,
14 Codec,
15 TranscodeEncodeErrorOf,
16 TranscodeEncoder,
17 TranscodeProgress,
18 Transcoder,
19};
20
21/// Encodes values into caller-provided output units by using a [`Codec`].
22///
23/// `CodecTranscodeEncoder` is the default bridge from the low-level unchecked
24/// [`Codec`] contract to the buffered [`Transcoder`] and
25/// [`TranscodeEncoder`] contracts. It encodes complete values only; when the
26/// remaining output capacity is smaller than `codec.encode_len(value)`, it
27/// stops before consuming that input value and reports
28/// [`crate::TranscodeStatus::NeedOutput`].
29///
30/// # Type Parameters
31///
32/// - `C`: Low-level codec used to encode values.
33#[derive(Debug)]
34pub struct CodecTranscodeEncoder<C> {
35 /// Common buffered encoding engine.
36 engine: TranscodeEncodeEngine<C, CodecTranscodeEncodeHooks>,
37}
38
39impl<C> CodecTranscodeEncoder<C>
40where
41 C: Codec,
42{
43 /// Creates a buffered encoder backed by `codec`.
44 ///
45 /// # Parameters
46 ///
47 /// - `codec`: Low-level codec used to encode values.
48 ///
49 /// # Returns
50 ///
51 /// Returns a buffered encoder adapter for the supplied codec.
52 #[inline]
53 #[must_use]
54 pub fn new(codec: C) -> Self {
55 Self {
56 engine: TranscodeEncodeEngine::new(
57 codec,
58 CodecTranscodeEncodeHooks,
59 ),
60 }
61 }
62
63 /// Returns a shared reference to the wrapped codec.
64 #[inline(always)]
65 #[must_use]
66 pub fn codec(&self) -> &C {
67 self.engine.codec()
68 }
69
70 /// Returns a mutable reference to the wrapped codec.
71 ///
72 /// Mutating a codec during an active stream can invalidate that stream's
73 /// assumptions; reset the adapter before continuing with the new codec
74 /// configuration.
75 #[inline(always)]
76 #[must_use]
77 pub fn codec_mut(&mut self) -> &mut C {
78 self.engine.codec_mut()
79 }
80
81 /// Consumes the adapter and returns its wrapped codec.
82 ///
83 /// Any buffered lifecycle state and internal hooks are discarded.
84 #[inline(always)]
85 #[must_use]
86 pub fn into_codec(self) -> C {
87 self.engine.into_parts().0
88 }
89}
90
91impl<C> Transcoder for CodecTranscodeEncoder<C>
92where
93 C: Codec,
94{
95 type Input = C::Value;
96 type Output = C::Unit;
97 type Error = TranscodeEncodeErrorOf<C>;
98
99 /// Gets the maximum number of output units needed for `input_len`
100 /// values.
101 ///
102 /// # Parameters
103 ///
104 /// - `input_len`: Logical input values the caller plans to encode.
105 ///
106 /// # Returns
107 ///
108 /// a conservative upper bound for output units.
109 #[inline(always)]
110 fn max_transcode_output_len(
111 &self,
112 input_len: usize,
113 ) -> Result<usize, CapacityError> {
114 self.engine.max_transcode_output_len(input_len)
115 }
116
117 /// Gets the global maximum units emitted when resetting internal state.
118 ///
119 /// # Returns
120 ///
121 /// the maximum units emitted when resetting internal state.
122 #[inline(always)]
123 fn max_reset_output_len(&self) -> Result<usize, CapacityError> {
124 self.engine.max_reset_output_len()
125 }
126
127 /// Gets the global maximum units emitted by finishing internal state.
128 ///
129 /// # Returns
130 ///
131 /// the number of units that may be emitted by finishing state.
132 #[inline(always)]
133 fn max_finish_output_len(&self) -> Result<usize, CapacityError> {
134 self.engine.max_finish_output_len()
135 }
136
137 /// Runs before-reset cleanup and emits stream-start output.
138 #[inline(always)]
139 fn reset(
140 &mut self,
141 output: &mut [C::Unit],
142 output_index: usize,
143 ) -> Result<usize, TranscodeEncodeErrorOf<C>> {
144 self.engine.reset(output, output_index)
145 }
146
147 /// Encodes values into the supplied output buffer.
148 ///
149 /// # Parameters
150 ///
151 /// - `input`: Input value slice.
152 /// - `input_index`: Absolute input index where encoding starts.
153 /// - `output`: Destination unit slice.
154 /// - `output_index`: Absolute output index where writing starts.
155 ///
156 /// # Returns
157 ///
158 /// Returns conversion progress for consumed input and produced output
159 /// units.
160 ///
161 /// # Errors
162 ///
163 /// Returns an encode error when indices are invalid or when encoding cannot
164 /// continue under current policy.
165 #[inline(always)]
166 fn transcode(
167 &mut self,
168 input: &[C::Value],
169 input_index: usize,
170 output: &mut [C::Unit],
171 output_index: usize,
172 ) -> Result<TranscodeProgress, TranscodeEncodeErrorOf<C>> {
173 self.engine
174 .transcode(input, input_index, output, output_index)
175 }
176
177 /// Finishes internally retained output after EOF.
178 ///
179 /// # Parameters
180 ///
181 /// - `output`: Destination unit slice for finalization output.
182 /// - `output_index`: Absolute output index where writing starts.
183 ///
184 /// # Returns
185 ///
186 /// Returns the number of units written by finalization.
187 ///
188 /// # Errors
189 ///
190 /// Returns a finish error if retained output cannot be fully emitted.
191 #[inline(always)]
192 fn finish(
193 &mut self,
194 output: &mut [C::Unit],
195 output_index: usize,
196 ) -> Result<usize, TranscodeEncodeErrorOf<C>> {
197 self.engine.finish(output, output_index)
198 }
199}
200
201impl<C> TranscodeEncoder for CodecTranscodeEncoder<C>
202where
203 C: Codec,
204{
205 type EncodeError = C::EncodeError;
206}
207
208impl<C> Default for CodecTranscodeEncoder<C>
209where
210 C: Codec + Default,
211{
212 /// Creates a default codec-backed buffered encoder.
213 ///
214 /// # Returns
215 ///
216 /// Returns an encoder backed by `C::default()`.
217 #[inline(always)]
218 fn default() -> Self {
219 Self::new(C::default())
220 }
221}