logos_codegen/graph/
impls.rs

1use std::fmt::{self, Debug, Display};
2use std::hash::{Hash, Hasher};
3
4use crate::graph::{Fork, Graph, Node, NodeId, Range, Rope};
5
6impl<T> From<Fork> for Node<T> {
7    fn from(fork: Fork) -> Self {
8        Node::Fork(fork)
9    }
10}
11impl<T> From<Rope> for Node<T> {
12    fn from(rope: Rope) -> Self {
13        Node::Rope(rope)
14    }
15}
16
17fn is_ascii(byte: u8) -> bool {
18    (0x20..0x7F).contains(&byte)
19}
20
21impl Hash for Fork {
22    fn hash<H: Hasher>(&self, state: &mut H) {
23        for branch in self.branches() {
24            branch.hash(state);
25        }
26        self.miss.hash(state);
27    }
28}
29
30impl<T> Hash for Node<T> {
31    fn hash<H: Hasher>(&self, state: &mut H) {
32        match self {
33            Node::Rope(rope) => {
34                b"ROPE".hash(state);
35                rope.hash(state);
36            }
37            Node::Fork(fork) => {
38                b"FORK".hash(state);
39                fork.hash(state);
40            }
41            Node::Leaf(_) => b"LEAF".hash(state),
42        }
43    }
44}
45
46impl Debug for NodeId {
47    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
48        Debug::fmt(&self.0, f)
49    }
50}
51
52/// We don't need debug impls in release builds
53// #[cfg(test)]
54mod debug {
55    use super::*;
56    use crate::graph::rope::Miss;
57    use crate::graph::Disambiguate;
58    use std::cmp::{Ord, Ordering};
59
60    impl Disambiguate for &str {
61        fn cmp(left: &&str, right: &&str) -> Ordering {
62            Ord::cmp(left, right)
63        }
64    }
65
66    impl Debug for Range {
67        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
68            let Range { start, end } = *self;
69
70            if start != end || !is_ascii(start) {
71                f.write_str("[")?;
72            }
73            match is_ascii(start) {
74                true => write!(f, "{}", start as char),
75                false => write!(f, "{:02X}", start),
76            }?;
77            if start != end {
78                match is_ascii(end) {
79                    true => write!(f, "-{}]", end as char),
80                    false => write!(f, "-{:02X}]", end),
81                }?;
82            } else if !is_ascii(start) {
83                f.write_str("]")?;
84            }
85            Ok(())
86        }
87    }
88
89    impl Display for Range {
90        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
91            <Range as Debug>::fmt(self, f)
92        }
93    }
94
95    impl<T: Debug> Debug for Graph<T> {
96        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
97            let entries = self
98                .nodes()
99                .iter()
100                .enumerate()
101                .filter_map(|(i, n)| n.as_ref().map(|n| (i, n)));
102
103            f.debug_map().entries(entries).finish()
104        }
105    }
106
107    struct Arm<T, U>(T, U);
108
109    impl<T, U> Debug for Arm<T, U>
110    where
111        T: Display,
112        U: Display,
113    {
114        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
115            write!(f, "{} ⇒ {}", self.0, self.1)
116        }
117    }
118
119    impl Debug for Fork {
120        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
121            let mut list = f.debug_set();
122
123            for (range, then) in self.branches() {
124                list.entry(&Arm(range, then));
125            }
126            if let Some(id) = self.miss {
127                list.entry(&Arm('_', id));
128            }
129
130            list.finish()
131        }
132    }
133
134    impl Display for Miss {
135        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
136            match self {
137                Miss::First(id) => Display::fmt(id, f),
138                Miss::Any(id) => write!(f, "{}*", id),
139                Miss::None => f.write_str("n/a"),
140            }
141        }
142    }
143
144    impl Debug for Rope {
145        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
146            use std::fmt::Write;
147
148            let mut rope = String::with_capacity(self.pattern.len());
149            for range in self.pattern.iter() {
150                write!(rope, "{}", range)?;
151            }
152
153            match self.miss.is_none() {
154                false => {
155                    let mut list = f.debug_list();
156
157                    list.entry(&Arm(rope, self.then));
158                    list.entry(&Arm('_', self.miss));
159
160                    list.finish()
161                }
162                true => Arm(rope, self.then).fmt(f),
163            }
164        }
165    }
166
167    impl PartialEq for Fork {
168        fn eq(&self, other: &Self) -> bool {
169            self.miss == other.miss && self.branches().eq(other.branches())
170        }
171    }
172
173    impl<T: Debug> Debug for Node<T> {
174        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
175            match self {
176                Node::Fork(fork) => fork.fmt(f),
177                Node::Rope(rope) => rope.fmt(f),
178                Node::Leaf(leaf) => leaf.fmt(f),
179            }
180        }
181    }
182
183    use std::ops::RangeInclusive;
184
185    impl From<RangeInclusive<u8>> for Range {
186        fn from(range: RangeInclusive<u8>) -> Range {
187            Range {
188                start: *range.start(),
189                end: *range.end(),
190            }
191        }
192    }
193
194    impl From<RangeInclusive<char>> for Range {
195        fn from(range: RangeInclusive<char>) -> Range {
196            Range {
197                start: *range.start() as u8,
198                end: *range.end() as u8,
199            }
200        }
201    }
202
203    impl<T> PartialEq<Rope> for Node<T> {
204        fn eq(&self, other: &Rope) -> bool {
205            match self {
206                Node::Rope(rope) => rope == other,
207                _ => false,
208            }
209        }
210    }
211
212    impl<T> PartialEq<Fork> for Node<T> {
213        fn eq(&self, other: &Fork) -> bool {
214            match self {
215                Node::Fork(fork) => fork == other,
216                _ => false,
217            }
218        }
219    }
220}