logos_codegen/graph/
range.rs

1use regex_syntax::hir::ClassBytesRange;
2use regex_syntax::hir::ClassUnicodeRange;
3use regex_syntax::utf8::Utf8Range;
4
5use std::cmp::{Ord, Ordering};
6
7#[derive(Clone, Copy, PartialEq, Eq, Hash)]
8pub struct Range {
9    pub start: u8,
10    pub end: u8,
11}
12
13impl Range {
14    pub fn as_byte(&self) -> Option<u8> {
15        if self.is_byte() {
16            Some(self.start)
17        } else {
18            None
19        }
20    }
21
22    pub fn is_byte(&self) -> bool {
23        self.start == self.end
24    }
25}
26
27impl From<u8> for Range {
28    fn from(byte: u8) -> Range {
29        Range {
30            start: byte,
31            end: byte,
32        }
33    }
34}
35
36impl From<&u8> for Range {
37    fn from(byte: &u8) -> Range {
38        Range::from(*byte)
39    }
40}
41
42impl Iterator for Range {
43    type Item = u8;
44
45    fn next(&mut self) -> Option<u8> {
46        match self.start.cmp(&self.end) {
47            std::cmp::Ordering::Less => {
48                let res = self.start;
49                self.start += 1;
50
51                Some(res)
52            }
53            std::cmp::Ordering::Equal => {
54                let res = self.start;
55
56                // Necessary so that range 0xFF-0xFF doesn't loop forever
57                self.start = 0xFF;
58                self.end = 0x00;
59
60                Some(res)
61            }
62            std::cmp::Ordering::Greater => None,
63        }
64    }
65}
66
67impl PartialOrd for Range {
68    fn partial_cmp(&self, other: &Range) -> Option<Ordering> {
69        Some(self.cmp(other))
70    }
71}
72
73impl Ord for Range {
74    fn cmp(&self, other: &Self) -> Ordering {
75        self.start.cmp(&other.start)
76    }
77}
78
79impl From<Utf8Range> for Range {
80    fn from(r: Utf8Range) -> Range {
81        Range {
82            start: r.start,
83            end: r.end,
84        }
85    }
86}
87
88impl From<ClassUnicodeRange> for Range {
89    fn from(r: ClassUnicodeRange) -> Range {
90        let start = r.start() as u32;
91        let end = r.end() as u32;
92
93        if start >= 128 || end >= 128 && end != 0x0010FFFF {
94            panic!("Casting non-ascii ClassUnicodeRange to Range")
95        }
96
97        Range {
98            start: start as u8,
99            end: end as u8,
100        }
101    }
102}
103
104impl From<ClassBytesRange> for Range {
105    fn from(r: ClassBytesRange) -> Range {
106        Range {
107            start: r.start(),
108            end: r.end(),
109        }
110    }
111}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116
117    #[test]
118    fn range_iter_one() {
119        let byte = Range::from(b'!');
120        let collected = byte.take(1000).collect::<Vec<_>>();
121
122        assert_eq!(b"!", &collected[..]);
123    }
124
125    #[test]
126    fn range_iter_few() {
127        let byte = Range {
128            start: b'a',
129            end: b'd',
130        };
131        let collected = byte.take(1000).collect::<Vec<_>>();
132
133        assert_eq!(b"abcd", &collected[..]);
134    }
135
136    #[test]
137    fn range_iter_bounds() {
138        let byte = Range::from(0xFA..=0xFF);
139
140        let collected = byte.take(1000).collect::<Vec<_>>();
141
142        assert_eq!(b"\xFA\xFB\xFC\xFD\xFE\xFF", &collected[..]);
143    }
144}