1#[cfg(not(feature = "std"))]
2use alloc::vec::Vec;
3
4#[cfg(not(feature = "std"))]
5use core as std;
6
7use bigint::BigUint;
8use DecodeError;
9
10pub(crate) trait Decoder<'a, 'b>
11where
12 <Self::Iter as Iterator>::Item: std::cmp::PartialEq + Copy,
13{
14 type Iter: std::iter::Iterator;
15
16 fn iter(_: &'a str) -> Self::Iter;
17 fn carry(&self, _: <Self::Iter as std::iter::Iterator>::Item) -> Option<u32>;
18 fn alphabet<'c>(&self) -> &'c [<Self::Iter as std::iter::Iterator>::Item]
19 where
20 'b: 'c;
21 fn decode(&self, input: &'a str) -> Result<Vec<u8>, DecodeError> {
22 if input.is_empty() {
23 return Ok(Vec::new());
24 }
25 let alpha = self.alphabet();
26 let base = alpha.len() as u32;
27
28 let mut big = BigUint::with_capacity(4);
29
30 for c in Self::iter(input) {
31 if let Some(carry) = self.carry(c) {
32 big.mul_add(base, carry);
33 } else {
34 return Err(DecodeError);
35 }
36 }
37
38 let mut bytes = big.into_bytes_be();
39
40 let leader = alpha[0];
41
42 let leaders = Self::iter(input).take_while(|byte| *byte == leader).count();
43
44 for _ in 0..leaders {
45 bytes.insert(0, 0);
46 }
47
48 Ok(bytes)
49 }
50}
51
52pub(crate) struct U8Decoder<'b> {
53 alphabet: &'b [u8],
54 lookup: [u8; 256],
55}
56
57impl<'a> U8Decoder<'a> {
58 #[inline]
59 pub(crate) fn new(alphabet: &'a [u8]) -> Self {
60 const INVALID_INDEX: u8 = 0xFF;
61 let mut lookup = [INVALID_INDEX; 256];
62
63 for (i, byte) in alphabet.iter().enumerate() {
64 lookup[*byte as usize] = i as u8;
65 }
66 U8Decoder { alphabet, lookup }
67 }
68}
69
70impl<'a, 'b> Decoder<'a, 'b> for U8Decoder<'b> {
71 type Iter = std::str::Bytes<'a>;
72 #[inline]
73 fn iter(s: &'a str) -> Self::Iter {
74 s.bytes()
75 }
76 #[inline]
77 fn carry(&self, c: u8) -> Option<u32> {
78 match self.lookup[c as usize] {
79 0xFF => None,
80 index => Some(index.into()),
81 }
82 }
83 #[inline]
84 fn alphabet<'c>(&self) -> &'c [u8]
85 where
86 'b: 'c,
87 {
88 self.alphabet
89 }
90}
91
92pub(crate) struct CharDecoder<'b>(pub &'b [char]);
93
94impl<'a, 'b> Decoder<'a, 'b> for CharDecoder<'b> {
95 type Iter = std::str::Chars<'a>;
96
97 #[inline]
98 fn iter(s: &'a str) -> Self::Iter {
99 s.chars()
100 }
101 #[inline]
102 fn carry(&self, c: char) -> Option<u32> {
103 self.0
104 .iter()
105 .enumerate()
106 .find(|&(_, ch)| *ch == c)
107 .map(|(i, _)| i as u32)
108 }
109 #[inline]
110 fn alphabet<'c>(&self) -> &'c [char]
111 where
112 'b: 'c,
113 {
114 self.0
115 }
116}