tm1637_embedded_hal/
str.rs

1//! [`str`] parsing utilities.
2
3use ::core::str::Bytes;
4
5use crate::mappings::{from_ascii_byte, SegmentBits};
6
7/// Parse a string to it's corresponding 7-segment display bits.
8///
9/// Dots are ignored unless they appear after a character. The dot is then or'd with the character.
10///
11/// # Example
12///
13/// ```rust
14/// use tm1637_embedded_hal::{str::StrParser, mappings::{DigitBits, LoCharBits, SegmentBits, UpCharBits}};
15///
16/// let input = "..oH.3..45..............6.7";
17/// let mut parser = StrParser::new(input);
18///
19/// assert_eq!(7, parser.len());
20/// assert_eq!(LoCharBits::LoO as u8, parser.next().unwrap());
21/// assert_eq!(UpCharBits::UpH as u8 | SegmentBits::Dot as u8, parser.next().unwrap());
22/// assert_eq!(DigitBits::Seven as u8, parser.next_back().unwrap());
23/// assert_eq!(4, parser.len());
24/// ```
25///
26#[derive(Debug, Clone)]
27pub struct StrParser<'a> {
28    bytes: Bytes<'a>,
29    current: Option<u8>,
30    /// While reading backwards, we need to know if we have read a dot.
31    ///
32    /// - `0`: No dot has been read.
33    /// - `SegmentBits::Dot as u8`: A dot has been read.
34    ///
35    /// We or this value with the found digit on the next call to `next_back`.
36    or: u8,
37    size: usize,
38}
39
40#[cfg(feature = "defmt")]
41impl defmt::Format for StrParser<'_> {
42    fn format(&self, fmt: defmt::Formatter) {
43        defmt::write!(fmt, "StrParser {{ .. }}")
44    }
45}
46
47impl<'a> StrParser<'a> {
48    /// Create a new [`StrParser`] from a &[`str`].
49    pub fn new(str: &'a str) -> Self {
50        Self {
51            bytes: str.bytes(),
52            current: None,
53            or: 0,
54            size: str.bytes().filter(|byte| *byte != b'.').count(),
55        }
56    }
57}
58
59impl<'a> From<&'a str> for StrParser<'a> {
60    fn from(value: &'a str) -> Self {
61        Self::new(value)
62    }
63}
64
65impl Iterator for StrParser<'_> {
66    type Item = u8;
67
68    fn next(&mut self) -> Option<Self::Item> {
69        if self.size == 0 {
70            return None;
71        }
72
73        loop {
74            match self.bytes.next() {
75                Some(byte) => match byte {
76                    b'.' => match self.current.take() {
77                        Some(current) => {
78                            self.size -= 1;
79
80                            return Some(from_ascii_byte(current) | SegmentBits::Dot as u8);
81                        }
82                        None => continue,
83                    },
84                    byte => match self.current.replace(byte) {
85                        Some(current) => {
86                            self.size -= 1;
87
88                            return Some(from_ascii_byte(current));
89                        }
90                        None => self.current = Some(byte),
91                    },
92                },
93                None => match self.current.take().map(from_ascii_byte) {
94                    Some(current) => {
95                        self.size -= 1;
96
97                        return Some(current);
98                    }
99                    None => return None,
100                },
101            }
102        }
103    }
104
105    fn size_hint(&self) -> (usize, Option<usize>) {
106        (self.size, Some(self.size))
107    }
108}
109
110impl ExactSizeIterator for StrParser<'_> {}
111
112impl DoubleEndedIterator for StrParser<'_> {
113    fn next_back(&mut self) -> Option<Self::Item> {
114        if self.size == 0 {
115            return None;
116        }
117
118        loop {
119            match self.bytes.next_back() {
120                Some(byte) => match byte {
121                    b'.' => {
122                        self.or = SegmentBits::Dot as u8;
123
124                        continue;
125                    }
126                    byte => {
127                        let byte = from_ascii_byte(byte) | self.or;
128
129                        self.or = 0;
130                        self.size -= 1;
131
132                        return Some(byte);
133                    }
134                },
135                None => match self.current.take() {
136                    Some(current) => {
137                        let byte = from_ascii_byte(current) | self.or;
138
139                        self.or = 0;
140                        self.size -= 1;
141
142                        return Some(byte);
143                    }
144                    None => return None,
145                },
146            }
147        }
148    }
149}
150
151#[cfg(test)]
152mod tests {
153    extern crate std;
154    use std::vec;
155    use std::vec::Vec;
156
157    use crate::mappings::{DigitBits, UpCharBits};
158
159    use super::*;
160
161    #[test]
162    fn no_dots() {
163        let parser = StrParser::new("1234");
164        let result: Vec<u8> = parser.collect();
165
166        assert_eq!(
167            vec![
168                DigitBits::One as u8,
169                DigitBits::Two as u8,
170                DigitBits::Three as u8,
171                DigitBits::Four as u8
172            ],
173            result
174        );
175    }
176
177    #[test]
178    fn len() {
179        let mut parser = StrParser::new("..12.3..45..............6.7");
180
181        assert_eq!(7, parser.len());
182        parser.next();
183        assert_eq!(6, parser.len());
184        parser.next();
185        assert_eq!(5, parser.len());
186        parser.next();
187        assert_eq!(4, parser.len());
188        parser.next();
189        assert_eq!(3, parser.len());
190        parser.next();
191        assert_eq!(2, parser.len());
192        parser.next();
193        assert_eq!(1, parser.len());
194        parser.next();
195        assert_eq!(0, parser.len());
196        assert_eq!(None, parser.next());
197        assert_eq!(0, parser.len());
198    }
199
200    #[test]
201    fn dots() {
202        let parser = StrParser::new("..12.3..45..............6.7");
203        let result: Vec<u8> = parser.collect();
204        assert_eq!(
205            vec![
206                DigitBits::One as u8,
207                DigitBits::Two as u8 | SegmentBits::Dot as u8,
208                DigitBits::Three as u8 | SegmentBits::Dot as u8,
209                DigitBits::Four as u8,
210                DigitBits::Five as u8 | SegmentBits::Dot as u8,
211                DigitBits::Six as u8 | SegmentBits::Dot as u8,
212                DigitBits::Seven as u8
213            ],
214            result
215        );
216    }
217
218    #[test]
219    fn no_dots_rev() {
220        let parser = StrParser::new("1234");
221        let result: Vec<u8> = parser.rev().collect();
222        let mut expected = vec![
223            DigitBits::One as u8,
224            DigitBits::Two as u8,
225            DigitBits::Three as u8,
226            DigitBits::Four as u8,
227        ];
228        expected.reverse();
229        assert_eq!(expected, result);
230    }
231
232    #[test]
233    fn dots_rev() {
234        let parser = StrParser::new("HE.LLO");
235        let result: Vec<u8> = parser.take(3).rev().collect();
236
237        assert_eq!(
238            vec![
239                UpCharBits::UpH as u8,
240                UpCharBits::UpE as u8 | SegmentBits::Dot as u8,
241                UpCharBits::UpL as u8,
242            ]
243            .into_iter()
244            .rev()
245            .collect::<Vec<_>>(),
246            result
247        );
248
249        let parser = StrParser::new("..12.3..45..............6.7");
250        let result: Vec<u8> = parser.rev().collect();
251        let mut expected = vec![
252            DigitBits::One as u8,
253            DigitBits::Two as u8 | SegmentBits::Dot as u8,
254            DigitBits::Three as u8 | SegmentBits::Dot as u8,
255            DigitBits::Four as u8,
256            DigitBits::Five as u8 | SegmentBits::Dot as u8,
257            DigitBits::Six as u8 | SegmentBits::Dot as u8,
258            DigitBits::Seven as u8,
259        ];
260        expected.reverse();
261        assert_eq!(expected, result);
262    }
263
264    #[test]
265    fn back_and_forth() {
266        let mut parser = StrParser::new("..12.3..45..............6.7");
267
268        assert_eq!(7, parser.len());
269
270        assert_eq!(Some(DigitBits::One as u8), parser.next());
271        assert_eq!(6, parser.len());
272
273        assert_eq!(
274            Some(DigitBits::Two as u8 | SegmentBits::Dot as u8),
275            parser.next()
276        );
277        assert_eq!(5, parser.len());
278
279        assert_eq!(Some(DigitBits::Seven as u8), parser.next_back());
280        assert_eq!(4, parser.len());
281
282        assert_eq!(
283            Some(DigitBits::Three as u8 | SegmentBits::Dot as u8),
284            parser.next()
285        );
286        assert_eq!(3, parser.len());
287
288        assert_eq!(
289            Some(DigitBits::Six as u8 | SegmentBits::Dot as u8),
290            parser.next_back()
291        );
292        assert_eq!(2, parser.len());
293
294        assert_eq!(Some(DigitBits::Four as u8), parser.next());
295        assert_eq!(1, parser.len());
296
297        assert_eq!(
298            Some(DigitBits::Five as u8 | SegmentBits::Dot as u8),
299            parser.next()
300        );
301        assert_eq!(0, parser.len());
302
303        assert_eq!(None, parser.next_back());
304        assert_eq!(None, parser.next());
305        assert_eq!(0, parser.len());
306    }
307
308    #[test]
309    fn overlap() {
310        let mut parser = StrParser::new("12345");
311
312        assert_eq!(5, parser.len());
313
314        assert_eq!(Some(DigitBits::One as u8), parser.next());
315        assert_eq!(4, parser.len());
316
317        assert_eq!(Some(DigitBits::Two as u8), parser.next());
318        assert_eq!(3, parser.len());
319
320        assert_eq!(Some(DigitBits::Three as u8), parser.next());
321        assert_eq!(2, parser.len());
322
323        assert_eq!(Some(DigitBits::Five as u8), parser.next_back());
324        assert_eq!(1, parser.len());
325
326        assert_eq!(Some(DigitBits::Four as u8), parser.next_back());
327        assert_eq!(0, parser.len());
328
329        assert_eq!(None, parser.next());
330        assert_eq!(None, parser.next_back());
331        assert_eq!(0, parser.len());
332    }
333
334    #[test]
335    fn overlap_dots_on_next() {
336        let mut parser = StrParser::new("12.3");
337
338        assert_eq!(3, parser.len());
339
340        assert_eq!(Some(DigitBits::One as u8), parser.next());
341        assert_eq!(2, parser.len());
342
343        assert_eq!(Some(DigitBits::Three as u8), parser.next_back());
344        assert_eq!(1, parser.len());
345
346        assert_eq!(
347            Some(DigitBits::Two as u8 | SegmentBits::Dot as u8),
348            parser.next()
349        );
350        assert_eq!(0, parser.len());
351
352        assert_eq!(None, parser.next());
353        assert_eq!(None, parser.next_back());
354        assert_eq!(0, parser.len());
355    }
356
357    #[test]
358    fn overlap_dots_on_next_back() {
359        let mut parser = StrParser::new("12...3");
360
361        assert_eq!(3, parser.len());
362
363        assert_eq!(Some(DigitBits::One as u8), parser.next());
364        assert_eq!(2, parser.len());
365
366        assert_eq!(Some(DigitBits::Three as u8), parser.next_back());
367        assert_eq!(1, parser.len());
368
369        assert_eq!(
370            Some(DigitBits::Two as u8 | SegmentBits::Dot as u8),
371            parser.next_back()
372        );
373        assert_eq!(0, parser.len());
374
375        assert_eq!(None, parser.next());
376        assert_eq!(None, parser.next_back());
377        assert_eq!(0, parser.len());
378    }
379}