use std::fmt::{self, Debug, Display}; use std::hash::{Hash, Hasher}; use crate::graph::{Fork, Graph, Node, NodeId, Range, Rope}; impl From for Node { fn from(fork: Fork) -> Self { Node::Fork(fork) } } impl From for Node { fn from(rope: Rope) -> Self { Node::Rope(rope) } } fn is_ascii(byte: u8) -> bool { (0x20..0x7F).contains(&byte) } impl Hash for Fork { fn hash(&self, state: &mut H) { for branch in self.branches() { branch.hash(state); } self.miss.hash(state); } } impl Hash for Node { fn hash(&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 { ::fmt(self, f) } } impl Debug for Graph { 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); impl Debug for Arm 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 Debug for Node { 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> for Range { fn from(range: RangeInclusive) -> Range { Range { start: *range.start(), end: *range.end(), } } } impl From> for Range { fn from(range: RangeInclusive) -> Range { Range { start: *range.start() as u8, end: *range.end() as u8, } } } impl PartialEq for Node { fn eq(&self, other: &Rope) -> bool { match self { Node::Rope(rope) => rope == other, _ => false, } } } impl PartialEq for Node { fn eq(&self, other: &Fork) -> bool { match self { Node::Fork(fork) => fork == other, _ => false, } } } }