bread_cli/
base.rs

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
48/// An iterator over Result<u8,[InError]>
49///
50/// Reads bytes from the input stream in the expected numeric base format, that means allowed
51/// characters depend on the particular numeric base (in any case in the ranges ('0', '9'), ('a', 'z') or ('A', 'Z'); any whitespace character is allowed and skipped)
52///
53/// [InError]: crate::error::InError
54pub 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
125/// Writes bytes to the output stream in the provided numeric base format
126///
127/// Produced characters depend on the particular numeric base, in any case in the range ('0', '9') and ('a','z')
128pub 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}