1use core::fmt;
2
3use crate::tables::{DECODE_FF, DECODE_TABLE};
4use crate::OutputTooSmall;
5
6#[non_exhaustive]
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
9pub struct DecodeOptions {
10 pub reject_non_alphabet: bool,
12}
13
14impl DecodeOptions {
15 pub const fn new() -> Self {
17 Self {
18 reject_non_alphabet: false,
19 }
20 }
21}
22
23impl Default for DecodeOptions {
24 fn default() -> Self {
25 Self::new()
26 }
27}
28
29#[non_exhaustive]
31#[derive(Clone, Copy, Debug, Eq, PartialEq)]
32pub enum DecodeError {
33 OutputTooSmall(OutputTooSmall),
35 InvalidByte { byte: u8, offset: usize },
37 #[cfg(feature = "alloc")]
39 AllocationFailed,
40}
41
42impl fmt::Display for DecodeError {
43 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
44 match self {
45 Self::OutputTooSmall(error) => error.fmt(formatter),
46 Self::InvalidByte { byte, offset } => {
47 write!(formatter, "invalid byte 0x{byte:02x} at offset {offset}")
48 }
49 #[cfg(feature = "alloc")]
50 Self::AllocationFailed => formatter.write_str("decoding allocation failed"),
51 }
52 }
53}
54
55impl core::error::Error for DecodeError {}
56
57pub const fn max_decoded_len(input_len: usize) -> Option<usize> {
71 let pairs = input_len / 2 + input_len % 2;
72 let prefix = match (pairs / 4).checked_mul(7) {
73 Some(value) => value,
74 None => return None,
75 };
76 let remaining_bytes = ((pairs % 4) * 14).div_ceil(8);
77 let tail = if input_len % 2 == 0 { 1 } else { 0 };
78 match prefix.checked_add(remaining_bytes) {
79 Some(value) => value.checked_add(tail),
80 None => None,
81 }
82}
83
84#[derive(Clone, Debug, Eq, PartialEq)]
100pub struct Decoder {
101 options: DecodeOptions,
102 pending: Option<u8>,
103 queue: u32,
104 nbits: u8,
105}
106
107impl Decoder {
108 pub const fn new(options: DecodeOptions) -> Self {
110 Self {
111 options,
112 pending: None,
113 queue: 0,
114 nbits: 0,
115 }
116 }
117
118 pub fn update(&mut self, input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
128 let required = self.update_capacity(input.len());
129 if output.len() < required {
130 return Err(DecodeError::OutputTooSmall(OutputTooSmall::new(required)));
131 }
132
133 if self.options.reject_non_alphabet {
134 self.update_strict(input, output)
135 } else {
136 Ok(self.update_lenient(input, output))
137 }
138 }
139
140 fn update_lenient(&mut self, input: &[u8], output: &mut [u8]) -> usize {
144 let mut queue = self.queue;
145 let mut nbits = u32::from(self.nbits);
146 let mut val = match self.pending {
147 Some(v) => u32::from(v),
148 None => u32::MAX,
149 };
150 let mut written = 0;
151
152 let emit_pair = |low: u32, high: u32, queue: &mut u32, nbits: &mut u32, out: &mut [u8]| {
153 let combined = low + high * 91;
154 *queue |= combined << *nbits;
155 *nbits += if combined & 8191 > 88 { 13 } else { 14 };
156 out[0] = *queue as u8;
157 *queue >>= 8;
158 *nbits -= 8;
159 if *nbits >= 8 {
160 out[1] = *queue as u8;
161 *queue >>= 8;
162 *nbits -= 8;
163 2
164 } else {
165 1
166 }
167 };
168
169 let len = input.len();
170 let mut i = 0;
171 while i < len {
172 if val == u32::MAX && i + 8 <= len && written + 8 <= output.len() {
179 let block = &input[i..i + 8];
180 let d0 = DECODE_FF[usize::from(block[0])];
181 let d1 = DECODE_FF[usize::from(block[1])];
182 let d2 = DECODE_FF[usize::from(block[2])];
183 let d3 = DECODE_FF[usize::from(block[3])];
184 let d4 = DECODE_FF[usize::from(block[4])];
185 let d5 = DECODE_FF[usize::from(block[5])];
186 let d6 = DECODE_FF[usize::from(block[6])];
187 let d7 = DECODE_FF[usize::from(block[7])];
188 if (d0 | d1 | d2 | d3 | d4 | d5 | d6 | d7) & 0x80 == 0 {
189 let out = &mut output[written..written + 8];
190 let mut w = 0;
191 w += emit_pair(
192 u32::from(d0),
193 u32::from(d1),
194 &mut queue,
195 &mut nbits,
196 &mut out[w..],
197 );
198 w += emit_pair(
199 u32::from(d2),
200 u32::from(d3),
201 &mut queue,
202 &mut nbits,
203 &mut out[w..],
204 );
205 w += emit_pair(
206 u32::from(d4),
207 u32::from(d5),
208 &mut queue,
209 &mut nbits,
210 &mut out[w..],
211 );
212 w += emit_pair(
213 u32::from(d6),
214 u32::from(d7),
215 &mut queue,
216 &mut nbits,
217 &mut out[w..],
218 );
219 written += w;
220 i += 8;
221 continue;
222 }
223 }
225
226 let d = DECODE_FF[usize::from(input[i])];
228 i += 1;
229 if d == 0xFF {
230 continue;
231 }
232 let d = u32::from(d);
233 if val == u32::MAX {
234 val = d;
235 continue;
236 }
237 written += emit_pair(val, d, &mut queue, &mut nbits, &mut output[written..]);
238 val = u32::MAX;
239 }
240 self.queue = queue;
241 self.nbits = nbits as u8;
242 self.pending = if val == u32::MAX {
243 None
244 } else {
245 Some(val as u8)
246 };
247 written
248 }
249
250 fn update_strict(&mut self, input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
254 let mut working = self.clone();
255 let mut written = 0;
256 for (offset, &byte) in input.iter().enumerate() {
257 let value = DECODE_TABLE[usize::from(byte)];
258 if value == 91 {
259 return Err(DecodeError::InvalidByte { byte, offset });
260 }
261 if let Some(first) = working.pending.take() {
262 let combined = u32::from(first) + u32::from(value) * 91;
263 working.queue |= combined << working.nbits;
264 working.nbits += if combined & 8191 > 88 { 13 } else { 14 };
265 while working.nbits > 7 {
266 output[written] = working.queue as u8;
267 written += 1;
268 working.queue >>= 8;
269 working.nbits -= 8;
270 }
271 } else {
272 working.pending = Some(value);
273 }
274 }
275 *self = working;
276 Ok(written)
277 }
278
279 pub fn finish(self) -> Result<Option<u8>, DecodeError> {
281 Ok(self
282 .pending
283 .map(|first| (self.queue | (u32::from(first) << self.nbits)) as u8))
284 }
285
286 pub(crate) fn decode_into(
287 mut self,
288 input: &[u8],
289 output: &mut [u8],
290 ) -> Result<usize, DecodeError> {
291 let required = one_shot_capacity(input.len());
292 if output.len() < required {
293 return Err(DecodeError::OutputTooSmall(OutputTooSmall::new(required)));
294 }
295
296 let written = self.update(input, output)?;
297 if let Some(byte) = self.finish()? {
298 output[written] = byte;
299 Ok(written + 1)
300 } else {
301 Ok(written)
302 }
303 }
304
305 fn update_capacity(&self, input_len: usize) -> usize {
306 let pairs = input_len / 2
307 + if self.pending.is_some() {
308 input_len % 2
309 } else {
310 0
311 };
312 let prefix = (pairs / 4).saturating_mul(7);
313 let remaining_bits = usize::from(self.nbits) + (pairs % 4) * 14;
314 prefix.saturating_add(remaining_bits / 8)
315 }
316}
317
318const fn one_shot_capacity(input_len: usize) -> usize {
319 let pairs = input_len / 2;
320 let prefix = (pairs / 4).saturating_mul(7);
321 let remaining_bytes = ((pairs % 4) * 14) / 8;
322 prefix
323 .saturating_add(remaining_bytes)
324 .saturating_add(input_len % 2)
325}
326
327#[cfg(feature = "alloc")]
328pub fn decode(input: &[u8], options: DecodeOptions) -> Result<alloc::vec::Vec<u8>, DecodeError> {
339 let capacity = max_decoded_len(input.len()).ok_or(DecodeError::AllocationFailed)?;
340 if capacity > isize::MAX as usize {
341 return Err(DecodeError::AllocationFailed);
342 }
343
344 let mut output = alloc::vec::Vec::new();
345 output
346 .try_reserve_exact(capacity)
347 .map_err(|_| DecodeError::AllocationFailed)?;
348 output.resize(capacity, 0);
349 let written = Decoder::new(options).decode_into(input, &mut output)?;
350 output.truncate(written);
351 Ok(output)
352}
353
354#[cfg(test)]
355mod tests {
356 use super::*;
357
358 #[test]
359 fn all_abstract_state_classes_are_reachable_and_shifts_fit_u32() {
360 let mut reachable = [[false; 8]; 2];
361 reachable[0][0] = true;
362
363 for _ in 0..32 {
364 let mut next = reachable;
365 for nbits in 0..=7 {
366 if reachable[0][nbits] {
367 next[1][nbits] = true;
368 }
369 if reachable[1][nbits] {
370 next[0][(nbits + 13) % 8] = true;
371 next[0][(nbits + 14) % 8] = true;
372 }
373 }
374 reachable = next;
375 }
376
377 assert!(reachable.into_iter().flatten().all(|state| state));
378 for nbits in 0..=7 {
379 let shifted = 8280_u32 << nbits;
380 assert!(shifted < (1_u32 << 21));
381 }
382 }
383
384 #[test]
385 fn update_capacity_matches_wide_formula() {
386 for pending in [None, Some(0)] {
387 for nbits in 0..=7 {
388 let decoder = Decoder {
389 options: DecodeOptions::new(),
390 pending,
391 queue: 0,
392 nbits,
393 };
394 for input_len in [0, 1, 2, 7, 8, 9, usize::MAX] {
395 let pairs = input_len as u128 / 2
396 + u128::from(pending.is_some()) * (input_len as u128 % 2);
397 let wide = (u128::from(nbits) + 14 * pairs) / 8;
398 let expected = usize::try_from(wide).unwrap_or(usize::MAX);
399 assert_eq!(decoder.update_capacity(input_len), expected);
400 }
401 }
402 }
403 }
404}