bread_cli/
hexadecimal.rs

1use crate::byte_writer::ByteWriter;
2use crate::error::{InError, OutError};
3use crate::util;
4use std::io::{Bytes, Read, Write};
5
6/// An iterator over Result<u8,[InError]>
7///
8/// Reads bytes from the input stream in hexadecimal base format, that is a multiple of 2 characters in the ranges ('0','9'), ('a','f') or ('A', 'F') are allowed (and any number of whitespace characters that will be skipped)
9///
10/// [InError]: crate::error::InError
11pub struct Reader<R: Read> {
12    in_bytes: Bytes<R>,
13}
14
15impl<R: Read> Reader<R> {
16    pub fn new(read: R) -> Self {
17        Reader {
18            in_bytes: read.bytes(),
19        }
20    }
21    fn valid(n: char) -> Option<u8> {
22        if ('0'..='9').contains(&n) {
23            Some(n as u8 - b'0')
24        } else if ('a'..='f').contains(&n) {
25            Some(10u8 + (n as u8 - b'a'))
26        } else if ('A'..='F').contains(&n) {
27            Some(10u8 + (n as u8 - b'A'))
28        } else {
29            None
30        }
31    }
32    fn next_non_whitespace(&mut self) -> Option<<Bytes<R> as Iterator>::Item> {
33        loop {
34            let c = self.in_bytes.next()?;
35            match c {
36                Ok(c) => {
37                    if c.is_ascii_whitespace() {
38                        continue;
39                    } else {
40                        return Some(Ok(c));
41                    }
42                }
43                Err(e) => {
44                    return Some(Err(e));
45                }
46            }
47        }
48    }
49}
50
51impl<R: Read> Iterator for Reader<R> {
52    type Item = Result<u8, InError>;
53    fn next(&mut self) -> Option<Self::Item> {
54        let msn = self.next_non_whitespace()?;
55        match msn {
56            Ok(msn) => {
57                if let Some(msn) = Self::valid(msn as char) {
58                    if let Some(lsn) = self.next_non_whitespace() {
59                        match lsn {
60                            Ok(lsn) => {
61                                if let Some(lsn) = Self::valid(lsn as char) {
62                                    Some(Ok((msn << 4) | lsn))
63                                } else {
64                                    Some(Err(InError::InvalidByte(lsn as char)))
65                                }
66                            }
67                            Err(e) => Some(Err(InError::StdIO(e))),
68                        }
69                    } else {
70                        Some(Err(InError::ShortIO {
71                            bytes: 1usize,
72                            expected: 2,
73                        }))
74                    }
75                } else {
76                    Some(Err(InError::InvalidByte(msn as char)))
77                }
78            }
79            Err(e) => Some(Err(InError::StdIO(e))),
80        }
81    }
82}
83
84/// Writes bytes to the output stream in the hexadecimal format
85///
86/// Produced characters are in the ranges ('0', '9') and ('a', 'f')
87pub struct Writer<W: Write> {
88    out_bytes: W,
89}
90
91impl<W: Write> Writer<W> {
92    pub fn new(out_bytes: W) -> Self {
93        Writer { out_bytes }
94    }
95}
96
97impl<W: Write> ByteWriter for Writer<W> {
98    fn write(&mut self, byte: u8) -> Result<(), OutError> {
99        let msn = char::from_digit(((byte & 0xf0) >> 4) as u32, 16).unwrap() as u8;
100        let lsn = char::from_digit((byte & 0x0f) as u32, 16).unwrap() as u8;
101        util::write(&mut self.out_bytes, &[msn, lsn], 2)
102    }
103}
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108    use crate::util::literals::*;
109
110    #[test]
111    fn read() {
112        let input = [_A, _4, _1, _B.to_ascii_uppercase()];
113        let mut reader = Reader::new(input.as_slice());
114        assert_eq!(0xa4u8, reader.next().unwrap().unwrap());
115        assert_eq!(0x1bu8, reader.next().unwrap().unwrap());
116        assert!(reader.next().is_none());
117    }
118
119    #[test]
120    fn write() {
121        let input = 0xf4;
122        let expected = [_F, _4];
123        let mut output = [0u8; 2];
124        let mut writer = Writer::new(output.as_mut_slice());
125        writer.write(input).unwrap();
126        assert_eq!(expected, output);
127    }
128}
129
130#[cfg(all(test, feature = "benchmark"))]
131mod benchs {
132    extern crate test;
133    use super::*;
134    use crate::util::literals::*;
135
136    #[bench]
137    fn read(b: &mut test::Bencher) {
138        const N: usize = 1024 * 1024;
139        static INPUT: [u8; N] = [_F; N];
140        b.iter(|| {
141            let reader = Reader::new(INPUT.as_slice());
142            let _ = reader.collect::<Vec<Result<u8, InError>>>();
143        });
144    }
145
146    #[bench]
147    fn write(b: &mut test::Bencher) {
148        const N: usize = 1024 * 1024;
149        static mut OUTPUT: [u8; N] = [_0; N];
150        b.iter(|| unsafe {
151            let mut writer = Writer::new(OUTPUT.as_mut_slice());
152            for _ in 0..N / 2 {
153                writer.write(255u8).unwrap();
154            }
155        });
156    }
157}