1use crate::byte_writer::ByteWriter;
2use crate::error::{InError, OutError};
3use crate::util;
4use crate::util::literals::*;
5use std::io::{Bytes, Read, Write};
6
7struct Base {
8 base: u8,
9 digits_per_byte: u8,
10}
11
12impl Base {
13 fn new(base: u8) -> Self {
14 Base {
15 base,
16 digits_per_byte: 256f32.log(base.into()).ceil() as u8,
17 }
18 }
19 fn valid(&self, n: char) -> Option<u8> {
20 let digit = if ('0'..='9').contains(&n) {
21 n as u8 - b'0'
22 } else if ('a'..='z').contains(&n) {
23 10u8 + (n as u8 - b'a')
24 } else if ('A'..='Z').contains(&n) {
25 10u8 + (n as u8 - b'A')
26 } else {
27 36u8
28 };
29 if digit < self.base {
30 Some(digit)
31 } else {
32 None
33 }
34 }
35 fn to_char(&self, d: u8) -> Option<u8> {
36 if d < self.base {
37 if d < 10 {
38 Some(_0 + d)
39 } else {
40 Some(_A + (d - 10))
41 }
42 } else {
43 None
44 }
45 }
46}
47
48pub struct Reader<R: Read> {
55 in_bytes: Bytes<R>,
56 base: Base,
57}
58
59impl<R: Read> Reader<R> {
60 pub fn new(read: R, base: u8) -> Self {
61 Reader {
62 in_bytes: read.bytes(),
63 base: Base::new(base),
64 }
65 }
66
67 fn next_non_whitespace(&mut self) -> Option<<Bytes<R> as Iterator>::Item> {
68 loop {
69 let c = self.in_bytes.next()?;
70 match c {
71 Ok(c) => {
72 if c.is_ascii_whitespace() {
73 continue;
74 } else {
75 return Some(Ok(c));
76 }
77 }
78 Err(e) => {
79 return Some(Err(e));
80 }
81 }
82 }
83 }
84}
85
86impl<R: Read> Iterator for Reader<R> {
87 type Item = Result<u8, InError>;
88 fn next(&mut self) -> Option<Self::Item> {
89 let mut value = 0u8;
90 let msi = (self.base.digits_per_byte - 1) as i8;
91 let mut i = msi as i8;
92 while i >= 0 {
93 let in_byte = self.next_non_whitespace();
94 match in_byte {
95 None => {
96 return if i == msi {
97 None
98 } else {
99 Some(Err(InError::ShortIO {
100 bytes: (msi - i) as usize,
101 expected: self.base.digits_per_byte as usize,
102 }))
103 }
104 }
105 Some(in_byte) => match in_byte {
106 Ok(in_byte) => {
107 let in_char = in_byte as char;
108 if let Some(digit) = self.base.valid(in_char) {
109 value += digit * self.base.base.pow(i as u32);
110 } else {
111 return Some(Err(InError::InvalidByte(in_char)));
112 }
113 }
114 Err(e) => {
115 return Some(Err(InError::StdIO(e)));
116 }
117 },
118 }
119 i -= 1;
120 }
121 Some(Ok(value))
122 }
123}
124
125pub struct Writer<W: Write> {
129 out_bytes: W,
130 base: Base,
131}
132
133impl<W: Write> Writer<W> {
134 pub fn new(out_bytes: W, base: u8) -> Self {
135 Writer {
136 out_bytes,
137 base: Base::new(base),
138 }
139 }
140}
141
142impl<W: Write> ByteWriter for Writer<W> {
143 fn write(&mut self, byte: u8) -> Result<(), OutError> {
144 let mut byte = byte;
145 let mut string = vec![_0; self.base.digits_per_byte as usize];
146 let mut i = string.len() - 1;
147 loop {
148 let digit = byte % self.base.base;
149 byte /= self.base.base;
150 string[i] = self.base.to_char(digit).unwrap();
151 if byte != 0 {
152 i -= 1;
153 } else {
154 break;
155 }
156 }
157 util::write(
158 &mut self.out_bytes,
159 string.as_slice(),
160 self.base.digits_per_byte as usize,
161 )
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168
169 const DIGITS: [u8; 36] = [
170 _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M,
171 _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z,
172 ];
173
174 fn required_digits(base: u8) -> u8 {
175 match base {
176 2 => 8,
177 3 => 6,
178 4..=6 => 4,
179 7..=15 => 3,
180 16..=36 => 2,
181 _ => panic!("invalid base {base}"),
182 }
183 }
184
185 #[test]
186 fn base_digits_per_byte() {
187 for base in 2..37 {
188 assert_eq!(Base::new(base).digits_per_byte, required_digits(base));
189 }
190 }
191
192 #[test]
193 fn base_valid_digits() {
194 for b in 2..37 {
195 let base = Base::new(b);
196 for value in 0..DIGITS.len() {
197 let digit = DIGITS[value];
198 let in_chars = [digit as char, (digit as char).to_ascii_uppercase()];
199 for in_char in in_chars {
200 let result = base.valid(in_char);
201 if value < b as usize {
202 assert_eq!(Some(value as u8), result);
203 } else {
204 assert_eq!(None, result, "base {b}, value: {value}");
205 }
206 }
207 }
208 assert_eq!(None, base.valid('*'));
209 assert_eq!(None, base.valid('!'));
210 }
211 }
212
213 #[test]
214 fn base_to_char() {
215 for b in 2..37 {
216 let base = Base::new(b);
217 for d in 0..b {
218 assert_eq!(Some(DIGITS[d as usize]), base.to_char(d));
219 }
220 assert_eq!(None, base.to_char(base.base));
221 assert_eq!(None, base.to_char(125));
222 }
223 }
224
225 #[test]
226 fn b2_read() {
227 let input = [
228 _0, _1, _0, _0, _1, _0, _1, _0, _0, _1, _0, _1, _1, _1, _1, _1,
229 ];
230 let mut reader = Reader::new(input.as_slice(), 2);
231 assert_eq!(0b01001010u8, reader.next().unwrap().unwrap());
232 assert_eq!(0b01011111u8, reader.next().unwrap().unwrap());
233 assert!(reader.next().is_none());
234 }
235
236 #[test]
237 fn b2_write() {
238 let input = 0b10110100u8;
239 let expected = [_1, _0, _1, _1, _0, _1, _0, _0];
240 let mut output = [0u8; 8];
241 let mut writer = Writer::new(output.as_mut_slice(), 2);
242 writer.write(input).unwrap();
243 assert_eq!(expected, output);
244 }
245
246 #[test]
247 fn b8_write0() {
248 let input = 0;
249 let expected = [_0, _0, _0];
250 let mut output = [0u8; 3];
251 let mut writer = Writer::new(output.as_mut_slice(), 8);
252 writer.write(input).unwrap();
253 assert_eq!(expected, output);
254 }
255
256 #[test]
257 fn b36_read() {
258 let mut input = [_0; DIGITS.len() * 2];
259 for i in 0..input.len() {
260 if i % 2 == 1 {
261 input[i] = DIGITS[i / 2];
262 }
263 }
264 let mut reader = Reader::new(input.as_slice(), 36);
265 for i in 0u8..36u8 {
266 let got = reader.next();
267 if got.is_none() {
268 panic!("reader.next() returned None for {i}");
269 }
270 let got = got.unwrap();
271 if got.is_err() {
272 panic!("{got:?} returned for {i}");
273 }
274 assert_eq!(i, got.unwrap());
275 }
276 assert!(reader.next().is_none());
277 }
278
279 #[test]
280 fn b36_write() {
281 let mut input = [0u8; 36];
282 let mut expected = [_0; 72];
283 for i in 0..DIGITS.len() {
284 input[i] = i as u8;
285 expected[2 * i + 1] = DIGITS[i];
286 }
287 let mut output = [0u8; 72];
288 let mut writer = Writer::new(output.as_mut_slice(), 36);
289 for b in input {
290 writer.write(b).unwrap();
291 }
292 assert_eq!(expected, output);
293 }
294}
295
296#[cfg(all(test, feature = "benchmark"))]
297mod benchs {
298 extern crate test;
299 use super::*;
300
301 #[bench]
302 fn b2_read(b: &mut test::Bencher) {
303 const N: usize = 1024 * 1024;
304 static INPUT: [u8; N] = [_1; N];
305 b.iter(|| {
306 let reader = Reader::new(INPUT.as_slice(), 2);
307 let _ = reader.collect::<Vec<Result<u8, InError>>>();
308 });
309 }
310
311 #[bench]
312 fn b2_write(b: &mut test::Bencher) {
313 const N: usize = 1024 * 1024;
314 static mut OUTPUT: [u8; N] = [_0; N];
315 b.iter(|| unsafe {
316 let mut writer = Writer::new(OUTPUT.as_mut_slice(), 2);
317 for _ in 0..N / 8 {
318 writer.write(255u8).unwrap();
319 }
320 });
321 }
322
323 #[bench]
324 fn b16_read(b: &mut test::Bencher) {
325 const N: usize = 1024 * 1024;
326 static INPUT: [u8; N] = [_F; N];
327 b.iter(|| {
328 let reader = Reader::new(INPUT.as_slice(), 16);
329 let _ = reader.collect::<Vec<Result<u8, InError>>>();
330 });
331 }
332
333 #[bench]
334 fn b16_write(b: &mut test::Bencher) {
335 const N: usize = 1024 * 1024;
336 static mut OUTPUT: [u8; N] = [_0; N];
337 b.iter(|| unsafe {
338 let mut writer = Writer::new(OUTPUT.as_mut_slice(), 16);
339 for _ in 0..N / 2 {
340 writer.write(255u8).unwrap();
341 }
342 });
343 }
344}