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