use std::ops::Deref; use crate::graph::{Disambiguate, Fork, Graph, NodeId, Range}; #[derive(PartialEq, Clone, Hash)] pub struct Rope { pub pattern: Pattern, pub then: NodeId, pub miss: Miss, } #[derive(PartialEq, Clone, Hash)] pub struct Pattern(pub Vec); impl Deref for Pattern { type Target = [Range]; fn deref(&self) -> &[Range] { &self.0 } } /// Because Ropes could potentially fail a match mid-pattern, /// a regular `Option` is not sufficient here. #[derive(PartialEq, Clone, Copy, Hash)] pub enum Miss { /// Same as Option::None, error on fail None, /// Jump to id if first byte does not match, fail on partial match First(NodeId), /// Jump to id on partial or empty match Any(NodeId), } impl Miss { pub fn is_none(&self) -> bool { matches!(self, Miss::None) } pub fn first(self) -> Option { match self { Miss::First(id) | Miss::Any(id) => Some(id), _ => None, } } pub fn take_first(&mut self) -> Option { match *self { Miss::First(id) => { *self = Miss::None; Some(id) } Miss::Any(id) => Some(id), Miss::None => None, } } } impl From> for Miss { fn from(miss: Option) -> Self { match miss { Some(id) => Miss::First(id), None => Miss::None, } } } impl From for Miss { fn from(id: NodeId) -> Self { Miss::First(id) } } impl Rope { pub fn new

(pattern: P, then: NodeId) -> Self where P: Into, { Rope { pattern: pattern.into(), then, miss: Miss::None, } } pub fn miss(mut self, miss: M) -> Self where M: Into, { self.miss = miss.into(); self } pub fn miss_any(mut self, miss: NodeId) -> Self { self.miss = Miss::Any(miss); self } pub fn into_fork(mut self, graph: &mut Graph) -> Fork where T: Disambiguate, { let first = self.pattern.0.remove(0); let miss = self.miss.take_first(); // The new fork will lead to a new rope, // or the old target if no new rope was created let then = match self.pattern.len() { 0 => self.then, _ => graph.push(self), }; Fork::new().branch(first, then).miss(miss) } pub fn prefix(&self, other: &Self) -> Option<(Pattern, Miss)> { let count = self .pattern .iter() .zip(other.pattern.iter()) .take_while(|(a, b)| a == b) .count(); let pattern = match count { 0 => return None, n => self.pattern[..n].into(), }; let miss = match (self.miss, other.miss) { (Miss::None, miss) => miss, (miss, Miss::None) => miss, _ => return None, }; Some((pattern, miss)) } pub fn split_at(mut self, at: usize, graph: &mut Graph) -> Option where T: Disambiguate, { match at { 0 => return None, n if n == self.pattern.len() => return Some(self), _ => (), } let (this, next) = self.pattern.split_at(at); let next_miss = match self.miss { Miss::Any(_) => self.miss, _ => Miss::None, }; let next = graph.push(Rope { pattern: next.into(), miss: next_miss, then: self.then, }); self.pattern = this.into(); self.then = next; Some(self) } pub fn remainder(mut self, at: usize, graph: &mut Graph) -> NodeId where T: Disambiguate, { self.pattern = self.pattern[at..].into(); match self.pattern.len() { 0 => self.then, _ => graph.push(self), } } pub fn shake(&self, graph: &Graph, filter: &mut [bool]) { if let Some(id) = self.miss.first() { if !filter[id.get()] { filter[id.get()] = true; graph[id].shake(graph, filter); } } if !filter[self.then.get()] { filter[self.then.get()] = true; graph[self.then].shake(graph, filter); } } } impl Pattern { pub fn to_bytes(&self) -> Option> { let mut out = Vec::with_capacity(self.len()); for range in self.iter() { out.push(range.as_byte()?); } Some(out) } } impl From<&[T]> for Pattern where T: Into + Copy, { fn from(slice: &[T]) -> Self { Pattern(slice.iter().copied().map(Into::into).collect()) } } impl From> for Pattern where T: Into, { fn from(vec: Vec) -> Self { Pattern(vec.into_iter().map(Into::into).collect()) } } impl From<&str> for Pattern { fn from(slice: &str) -> Self { slice.as_bytes().into() } } #[cfg(test)] mod tests { use super::*; use crate::graph::Node; use pretty_assertions::assert_eq; #[test] fn into_fork() { let mut graph = Graph::new(); let leaf = graph.push(Node::Leaf("LEAF")); let rope = Rope::new("foobar", leaf); let fork = rope.into_fork(&mut graph); assert_eq!(leaf, NodeId::new(1)); assert_eq!(fork, Fork::new().branch(b'f', NodeId::new(2))); assert_eq!(graph[NodeId::new(2)], Rope::new("oobar", leaf)); } #[test] fn into_fork_one_byte() { let mut graph = Graph::new(); let leaf = graph.push(Node::Leaf("LEAF")); let rope = Rope::new("!", leaf); let fork = rope.into_fork(&mut graph); assert_eq!(leaf, NodeId::new(1)); assert_eq!(fork, Fork::new().branch(b'!', NodeId::new(1))); } #[test] fn into_fork_miss_any() { let mut graph = Graph::new(); let leaf = graph.push(Node::Leaf("LEAF")); let rope = Rope::new("42", leaf).miss_any(NodeId::new(42)); let fork = rope.into_fork(&mut graph); assert_eq!(leaf, NodeId::new(1)); assert_eq!( fork, Fork::new() .branch(b'4', NodeId::new(2)) .miss(NodeId::new(42)) ); assert_eq!( graph[NodeId::new(2)], Rope::new("2", leaf).miss_any(NodeId::new(42)) ); } #[test] fn into_fork_miss_first() { let mut graph = Graph::new(); let leaf = graph.push(Node::Leaf("LEAF")); let rope = Rope::new("42", leaf).miss(Miss::First(NodeId::new(42))); let fork = rope.into_fork(&mut graph); assert_eq!(leaf, NodeId::new(1)); assert_eq!( fork, Fork::new() .branch(b'4', NodeId::new(2)) .miss(NodeId::new(42)) ); assert_eq!(graph[NodeId::new(2)], Rope::new("2", leaf)); } #[test] fn split_at() { let mut graph = Graph::new(); let leaf = graph.push(Node::Leaf("LEAF")); let rope = Rope::new("foobar", leaf); assert_eq!(rope.clone().split_at(6, &mut graph).unwrap(), rope); let split = rope.split_at(3, &mut graph).unwrap(); let expected_id = NodeId::new(leaf.get() + 1); assert_eq!(split, Rope::new("foo", expected_id)); assert_eq!(graph[expected_id], Rope::new("bar", leaf)); } #[test] fn pattern_to_bytes() { let pat = Pattern::from("foobar"); assert_eq!(pat.to_bytes().unwrap(), b"foobar"); let ranges = Pattern::from(vec![0..=0, 42..=42, b'{'..=b'}']); assert_eq!(ranges.to_bytes(), None); } }