qubit_io/coder/coder.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2026 Haixing Hu.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10use super::coder_progress::CoderProgress;
11
12/// Converts one sequence of code units into another sequence of code units.
13///
14/// `convert` is the main streaming API. It transforms a provided input segment and
15/// writes as much output as available buffer space allows, without automatically
16/// flushing internal pending state.
17///
18/// The method is suitable for:
19/// - pull-style consumers that call conversion repeatedly as buffers arrive;
20/// - bounded output sinks that need `NeedOutput` progress when capacity is hit;
21/// - stateless and stateful codecs that all return progress-oriented stopping
22/// reasons.
23///
24/// `Coder` is intentionally independent from any charset semantics:
25///
26/// - Use `Coder` directly for custom, policy-free unit transforms.
27/// - Use `Coder` when you want to own malformed/unmappable decisions at the call site.
28///
29/// # Example: streaming byte-to-word decoder
30///
31/// ```rust
32/// use qubit_io::{Coder, CoderProgress, CoderStatus};
33///
34/// #[derive(Default)]
35/// struct U16BeBytesDecoder;
36///
37/// impl Coder<u8, u16> for U16BeBytesDecoder {
38/// type Error = core::convert::Infallible;
39///
40/// fn max_output_len(&self, input_len: usize) -> Option<usize> {
41/// Some(input_len / 2)
42/// }
43///
44/// fn convert(
45/// &mut self,
46/// input: &[u8],
47/// input_index: usize,
48/// output: &mut [u16],
49/// output_index: usize,
50/// ) -> Result<CoderProgress, Self::Error> {
51/// let mut read = 0;
52/// let mut written = 0;
53/// while input_index + read + 1 < input.len() {
54/// if output_index + written == output.len() {
55/// let status = CoderStatus::NeedOutput {
56/// output_index: output_index + written,
57/// required: 1,
58/// available: 0,
59/// };
60/// return Ok(CoderProgress::new(status, read, written));
61/// }
62/// let high = input[input_index + read] as u16;
63/// let low = input[input_index + read + 1] as u16;
64/// output[output_index + written] = (high << 8) | low;
65/// read += 2;
66/// written += 1;
67/// }
68/// if input_index + read == input.len() {
69/// Ok(CoderProgress::complete(read, written))
70/// } else {
71/// let status = CoderStatus::NeedInput {
72/// input_index: input_index + read,
73/// required: 2,
74/// available: input.len() - (input_index + read),
75/// };
76/// Ok(CoderProgress::new(status, read, written))
77/// }
78/// }
79/// }
80///
81/// let mut coder = U16BeBytesDecoder;
82/// let mut output = [0_u16; 1];
83/// let progress = coder
84/// .convert(&[0x12, 0x34, 0xab, 0xcd], 0, &mut output, 0)
85/// .expect("decoding cannot fail");
86/// assert_eq!(CoderStatus::NeedOutput {
87/// output_index: 1,
88/// required: 1,
89/// available: 0,
90/// }, progress.status());
91/// assert_eq!(2, progress.read());
92/// assert_eq!(1, progress.written());
93/// assert_eq!([0x1234], output);
94///
95/// let mut output = [0_u16; 2];
96/// let progress = coder
97/// .convert(&[0x12, 0x34, 0xab], 0, &mut output, 0)
98/// .expect("decoding cannot fail");
99/// assert_eq!(CoderStatus::NeedInput {
100/// input_index: 2,
101/// required: 2,
102/// available: 1,
103/// }, progress.status());
104/// assert_eq!(2, progress.read());
105/// assert_eq!(1, progress.written());
106/// assert_eq!([0x1234, 0], output);
107/// ```
108///
109/// The trait is intentionally independent from charset concepts. Implementors
110/// use `input_index` and `output_index` as absolute positions in the supplied
111/// slices. Returned progress counters are relative counts from those positions.
112/// For raw codecs this gives a compact API; higher-level workflows can wrap this
113/// trait with their own semantic policies.
114///
115/// # Type Parameters
116///
117/// - `Input`: Input unit type accepted by this coder.
118/// - `Output`: Output unit type produced by this coder.
119pub trait Coder<Input, Output> {
120 /// Error reported for semantic conversion failures.
121 type Error;
122
123 /// Returns an upper bound for output units produced from `input_len` units.
124 ///
125 /// # Parameters
126 ///
127 /// - `input_len`: Number of input units the caller plans to convert.
128 ///
129 /// # Returns
130 ///
131 /// Returns `Some(bound)` when the coder can provide a finite upper bound.
132 /// Returns `None` when the bound is not known.
133 #[must_use]
134 fn max_output_len(&self, input_len: usize) -> Option<usize>;
135
136 /// Resets state retained between conversion calls.
137 ///
138 /// Stateless coders may keep the default no-op implementation.
139 #[inline]
140 fn reset(&mut self) {}
141
142 /// Converts input units into output units.
143 ///
144 /// # Parameters
145 ///
146 /// - `input`: Complete input unit slice visible to the coder.
147 /// - `input_index`: Absolute input unit index where conversion starts.
148 /// - `output`: Complete output unit slice visible to the coder.
149 /// - `output_index`: Absolute output unit index where writing starts.
150 ///
151 /// # Returns
152 ///
153 /// Returns progress describing how many units were consumed and produced and
154 /// why conversion stopped.
155 ///
156 /// # Errors
157 ///
158 /// Returns `Self::Error` for semantic conversion failures that the coder's
159 /// policy does not absorb.
160 fn convert(
161 &mut self,
162 input: &[Input],
163 input_index: usize,
164 output: &mut [Output],
165 output_index: usize,
166 ) -> Result<CoderProgress, Self::Error>;
167
168 /// Flushes any buffered output after input conversion is complete.
169 ///
170 /// `convert` handles input consumption. `finish` is called only after all
171 /// source input has been provided and is used to flush buffered state
172 /// (for example, a pending decoded character).
173 ///
174 /// # Example
175 ///
176 /// ```rust
177 /// use qubit_io::{Coder, CoderStatus};
178 ///
179 /// #[derive(Default)]
180 /// struct ByteCopy;
181 ///
182 /// impl Coder<u8, u8> for ByteCopy {
183 /// type Error = core::convert::Infallible;
184 ///
185 /// fn max_output_len(&self, input_len: usize) -> Option<usize> {
186 /// Some(input_len)
187 /// }
188 ///
189 /// fn convert(
190 /// &mut self,
191 /// input: &[u8],
192 /// input_index: usize,
193 /// output: &mut [u8],
194 /// output_index: usize,
195 /// ) -> Result<qubit_io::CoderProgress, Self::Error> {
196 /// let mut read = 0;
197 /// let mut written = 0;
198 /// while input_index + read < input.len() && output_index + written < output.len() {
199 /// output[output_index + written] = input[input_index + read];
200 /// read += 1;
201 /// written += 1;
202 /// }
203 /// if input_index + read == input.len() {
204 /// Ok(qubit_io::CoderProgress::complete(read, written))
205 /// } else {
206 /// let status = qubit_io::CoderStatus::NeedOutput {
207 /// output_index: output_index + written,
208 /// required: 1,
209 /// available: output.len().saturating_sub(output_index + written),
210 /// };
211 /// Ok(qubit_io::CoderProgress::new(
212 /// status,
213 /// read,
214 /// written,
215 /// ))
216 /// }
217 /// }
218 /// }
219 ///
220 /// let mut coder = ByteCopy;
221 /// let mut output = [1_u8; 1];
222 /// let progress = coder
223 /// .convert(&[7], 0, &mut output, 0)
224 /// .expect("writer consumes one unit");
225 /// assert_eq!(CoderStatus::Complete, progress.status());
226 ///
227 /// let finish = coder
228 /// .finish(&mut output, 1)
229 /// .expect("finish does not emit buffered state for no-op coders");
230 /// assert_eq!(CoderStatus::Complete, finish.status());
231 /// ```
232 ///
233 /// # Parameters
234 ///
235 /// - `output`: Complete output unit slice visible to the coder.
236 /// - `output_index`: Absolute output unit index where writing starts.
237 ///
238 /// # Returns
239 ///
240 /// Returns progress for units written during flushing. Stateless coders
241 /// return a completed progress value with zero counters.
242 ///
243 /// # Errors
244 ///
245 /// Returns `Self::Error` if pending state cannot be flushed according to the
246 /// coder's policy.
247 #[inline]
248 fn finish(&mut self, _output: &mut [Output], _output_index: usize) -> Result<CoderProgress, Self::Error> {
249 Ok(CoderProgress::complete(0, 0))
250 }
251}