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