diff --git a/src/block.rs b/src/block.rs index 484d95c..51b5a36 100644 --- a/src/block.rs +++ b/src/block.rs @@ -418,7 +418,7 @@ mod test { macro_rules! test_parse { ($src:expr $(,$($event:expr),* $(,)?)?) => { let t = super::TreeParser::new($src).parse(); - let actual = t.map(|ev| (ev.kind, ev.span.of($src))).collect::>(); + let actual = t.root().map(|ev| (ev.kind, ev.span.of($src))).collect::>(); let expected = &[$($($event),*,)?]; assert_eq!(actual, expected, "\n\n{}\n\n", $src); }; diff --git a/src/lib.rs b/src/lib.rs index d0c662b..d3ed415 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -265,10 +265,12 @@ impl<'s> Container<'s> { pub struct Parser<'s> { src: &'s str, - tree: block::Tree, + tree: tree::Branch, inlines: span::InlineSpans<'s>, inline_parser: Option>>, link_definitions: std::collections::HashMap<&'s str, String>, + + _tree_data: block::Tree, } impl<'s> Parser<'s> { @@ -277,27 +279,30 @@ impl<'s> Parser<'s> { let tree = block::parse(src); let link_definitions = { - let mut tree = tree.clone(); // TODO avoid clone + let mut branch = tree.root(); let mut defs = std::collections::HashMap::new(); - while let Some(e) = tree.next() { + while let Some(e) = branch.next() { if let tree::EventKind::Enter(block::Node::Leaf(block::Leaf::LinkDefinition)) = e.kind { let tag = e.span.of(src); // TODO borrow url string if single inline - let url = tree.inlines().map(|sp| sp.of(src).trim()).collect(); + let url = branch.take_inlines().map(|sp| sp.of(src).trim()).collect(); defs.insert(tag, url); } } defs }; + let branch = tree.root(); + Self { src, - tree, + tree: branch, inlines: span::InlineSpans::new(src), inline_parser: None, link_definitions, + _tree_data: tree, } } } @@ -423,12 +428,12 @@ impl<'s> Parser<'s> { if matches!(c, block::Node::Leaf(block::Leaf::LinkDefinition)) => { // ignore link definitions - self.tree.inlines().last(); + self.tree.take_inlines().last(); continue; } tree::EventKind::Enter(c) => match c { block::Node::Leaf(l) => { - self.inlines.set_spans(self.tree.inlines()); + self.inlines.set_spans(self.tree.take_inlines()); self.inline_parser = Some(inline::Parser::new(self.inlines.chars())); let container = Container::from_leaf_block(content, l); Event::Start(container, attributes) diff --git a/src/tree.rs b/src/tree.rs index 11f8f79..eb53b4e 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -14,12 +14,7 @@ pub struct Event { pub span: Span, } -#[derive(Clone)] -pub struct Tree { - nodes: Vec>, - branch: Vec, - head: Option, -} +pub struct Tree(Box<[Node]>); #[derive(Clone)] pub struct Inlines<'t, C, A> { @@ -35,28 +30,34 @@ impl<'t, C, A> Iterator for Inlines<'t, C, A> { } impl Tree { - fn new(nodes: Vec>) -> Self { - let head = nodes[NodeIndex::root().index()].next; - Self { + pub fn root(&self) -> Branch { + let head = self.0[NodeIndex::root().index()].next; + // SAFETY: tree must outlive the branch + let nodes = unsafe { std::mem::transmute::<&[Node], &'static [Node]>(&self.0) }; + Branch { nodes, branch: Vec::new(), head, } } +} - pub fn inlines(&self) -> Inlines { - let start = self.nodes[self.head.unwrap().index()].next.unwrap().index(); - let end = start + self.spans().count(); - Inlines { - iter: self.nodes[start..end].iter(), - } - } +#[derive(Clone)] +pub struct Branch { + nodes: &'static [Node], + branch: Vec, + head: Option, +} - pub fn spans(&self) -> impl Iterator + '_ { - let mut head = self.head; +impl Branch { + /// Retrieve all inlines until the end of the current container. Panics if any upcoming node is + /// not an inline node. + pub fn take_inlines(&mut self) -> impl Iterator + '_ { + let mut head = self.head.take(); std::iter::from_fn(move || { head.take().map(|h| { let n = &self.nodes[h.index()]; + assert!(matches!(n.kind, NodeKind::Inline)); head = n.next; n.span }) @@ -64,7 +65,7 @@ impl Tree { } } -impl Iterator for Tree { +impl Iterator for Branch { type Item = Event; fn next(&mut self) -> Option { @@ -188,7 +189,7 @@ impl Builder { } pub(super) fn finish(self) -> Tree { - Tree::new(self.nodes) + Tree(self.nodes.into_boxed_slice()) } fn add_node(&mut self, node: Node) { @@ -220,13 +221,15 @@ impl Builder { } } -impl std::fmt::Debug for Builder { +impl std::fmt::Debug + for Builder +{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.clone().finish().fmt(f) + self.clone().finish().root().fmt(f) } } -impl std::fmt::Debug for Tree { +impl std::fmt::Debug for Branch { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { const INDENT: &str = " "; let mut level = 0;