diff options
Diffstat (limited to 'vendor/logos-codegen/src/graph/impls.rs')
| -rw-r--r-- | vendor/logos-codegen/src/graph/impls.rs | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/vendor/logos-codegen/src/graph/impls.rs b/vendor/logos-codegen/src/graph/impls.rs new file mode 100644 index 00000000..dc97bdf1 --- /dev/null +++ b/vendor/logos-codegen/src/graph/impls.rs @@ -0,0 +1,220 @@ +use std::fmt::{self, Debug, Display}; +use std::hash::{Hash, Hasher}; + +use crate::graph::{Fork, Graph, Node, NodeId, Range, Rope}; + +impl<T> From<Fork> for Node<T> { + fn from(fork: Fork) -> Self { + Node::Fork(fork) + } +} +impl<T> From<Rope> for Node<T> { + fn from(rope: Rope) -> Self { + Node::Rope(rope) + } +} + +fn is_ascii(byte: u8) -> bool { + (0x20..0x7F).contains(&byte) +} + +impl Hash for Fork { + fn hash<H: Hasher>(&self, state: &mut H) { + for branch in self.branches() { + branch.hash(state); + } + self.miss.hash(state); + } +} + +impl<T> Hash for Node<T> { + fn hash<H: Hasher>(&self, state: &mut H) { + match self { + Node::Rope(rope) => { + b"ROPE".hash(state); + rope.hash(state); + } + Node::Fork(fork) => { + b"FORK".hash(state); + fork.hash(state); + } + Node::Leaf(_) => b"LEAF".hash(state), + } + } +} + +impl Debug for NodeId { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.0, f) + } +} + +/// We don't need debug impls in release builds +// #[cfg(test)] +mod debug { + use super::*; + use crate::graph::rope::Miss; + use crate::graph::Disambiguate; + use std::cmp::{Ord, Ordering}; + + impl Disambiguate for &str { + fn cmp(left: &&str, right: &&str) -> Ordering { + Ord::cmp(left, right) + } + } + + impl Debug for Range { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let Range { start, end } = *self; + + if start != end || !is_ascii(start) { + f.write_str("[")?; + } + match is_ascii(start) { + true => write!(f, "{}", start as char), + false => write!(f, "{:02X}", start), + }?; + if start != end { + match is_ascii(end) { + true => write!(f, "-{}]", end as char), + false => write!(f, "-{:02X}]", end), + }?; + } else if !is_ascii(start) { + f.write_str("]")?; + } + Ok(()) + } + } + + impl Display for Range { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + <Range as Debug>::fmt(self, f) + } + } + + impl<T: Debug> Debug for Graph<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let entries = self + .nodes() + .iter() + .enumerate() + .filter_map(|(i, n)| n.as_ref().map(|n| (i, n))); + + f.debug_map().entries(entries).finish() + } + } + + struct Arm<T, U>(T, U); + + impl<T, U> Debug for Arm<T, U> + where + T: Display, + U: Display, + { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} ⇒ {}", self.0, self.1) + } + } + + impl Debug for Fork { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut list = f.debug_set(); + + for (range, then) in self.branches() { + list.entry(&Arm(range, then)); + } + if let Some(id) = self.miss { + list.entry(&Arm('_', id)); + } + + list.finish() + } + } + + impl Display for Miss { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Miss::First(id) => Display::fmt(id, f), + Miss::Any(id) => write!(f, "{}*", id), + Miss::None => f.write_str("n/a"), + } + } + } + + impl Debug for Rope { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use std::fmt::Write; + + let mut rope = String::with_capacity(self.pattern.len()); + for range in self.pattern.iter() { + write!(rope, "{}", range)?; + } + + match self.miss.is_none() { + false => { + let mut list = f.debug_list(); + + list.entry(&Arm(rope, self.then)); + list.entry(&Arm('_', self.miss)); + + list.finish() + } + true => Arm(rope, self.then).fmt(f), + } + } + } + + impl PartialEq for Fork { + fn eq(&self, other: &Self) -> bool { + self.miss == other.miss && self.branches().eq(other.branches()) + } + } + + impl<T: Debug> Debug for Node<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Node::Fork(fork) => fork.fmt(f), + Node::Rope(rope) => rope.fmt(f), + Node::Leaf(leaf) => leaf.fmt(f), + } + } + } + + use std::ops::RangeInclusive; + + impl From<RangeInclusive<u8>> for Range { + fn from(range: RangeInclusive<u8>) -> Range { + Range { + start: *range.start(), + end: *range.end(), + } + } + } + + impl From<RangeInclusive<char>> for Range { + fn from(range: RangeInclusive<char>) -> Range { + Range { + start: *range.start() as u8, + end: *range.end() as u8, + } + } + } + + impl<T> PartialEq<Rope> for Node<T> { + fn eq(&self, other: &Rope) -> bool { + match self { + Node::Rope(rope) => rope == other, + _ => false, + } + } + } + + impl<T> PartialEq<Fork> for Node<T> { + fn eq(&self, other: &Fork) -> bool { + match self { + Node::Fork(fork) => fork == other, + _ => false, + } + } + } +} |
