tree: add tree branch reference

allow multiple independent iterators for the same underlying tree

safety: not very good, but should work because original tree is kept in
Parser and branches are only used during its lifetime
This commit is contained in:
Noah Hellman 2023-01-18 21:33:55 +01:00
parent 4a7967812e
commit c7b3aa560b
3 changed files with 39 additions and 31 deletions

View file

@ -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::<Vec<_>>();
let actual = t.root().map(|ev| (ev.kind, ev.span.of($src))).collect::<Vec<_>>();
let expected = &[$($($event),*,)?];
assert_eq!(actual, expected, "\n\n{}\n\n", $src);
};

View file

@ -265,10 +265,12 @@ impl<'s> Container<'s> {
pub struct Parser<'s> {
src: &'s str,
tree: block::Tree,
tree: tree::Branch<block::Node, block::Atom>,
inlines: span::InlineSpans<'s>,
inline_parser: Option<inline::Parser<span::InlineCharsIter<'s>>>,
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)

View file

@ -14,12 +14,7 @@ pub struct Event<C, A> {
pub span: Span,
}
#[derive(Clone)]
pub struct Tree<C, A> {
nodes: Vec<Node<C, A>>,
branch: Vec<NodeIndex>,
head: Option<NodeIndex>,
}
pub struct Tree<C, A>(Box<[Node<C, A>]>);
#[derive(Clone)]
pub struct Inlines<'t, C, A> {
@ -35,28 +30,34 @@ impl<'t, C, A> Iterator for Inlines<'t, C, A> {
}
impl<C, A> Tree<C, A> {
fn new(nodes: Vec<Node<C, A>>) -> Self {
let head = nodes[NodeIndex::root().index()].next;
Self {
pub fn root(&self) -> Branch<C, A> {
let head = self.0[NodeIndex::root().index()].next;
// SAFETY: tree must outlive the branch
let nodes = unsafe { std::mem::transmute::<&[Node<C, A>], &'static [Node<C, A>]>(&self.0) };
Branch {
nodes,
branch: Vec::new(),
head,
}
}
pub fn inlines(&self) -> Inlines<C, A> {
let start = self.nodes[self.head.unwrap().index()].next.unwrap().index();
let end = start + self.spans().count();
Inlines {
iter: self.nodes[start..end].iter(),
}
}
pub fn spans(&self) -> impl Iterator<Item = Span> + '_ {
let mut head = self.head;
#[derive(Clone)]
pub struct Branch<C: 'static, A: 'static> {
nodes: &'static [Node<C, A>],
branch: Vec<NodeIndex>,
head: Option<NodeIndex>,
}
impl<C, A> Branch<C, A> {
/// 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<Item = Span> + '_ {
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<C, A> Tree<C, A> {
}
}
impl<C: Clone, A: Clone> Iterator for Tree<C, A> {
impl<C: Clone, A: Clone> Iterator for Branch<C, A> {
type Item = Event<C, A>;
fn next(&mut self) -> Option<Self::Item> {
@ -188,7 +189,7 @@ impl<C: Clone, A: Clone> Builder<C, A> {
}
pub(super) fn finish(self) -> Tree<C, A> {
Tree::new(self.nodes)
Tree(self.nodes.into_boxed_slice())
}
fn add_node(&mut self, node: Node<C, A>) {
@ -220,13 +221,15 @@ impl<C: Clone, A: Clone> Builder<C, A> {
}
}
impl<C: std::fmt::Debug + Clone, A: std::fmt::Debug + Clone> std::fmt::Debug for Builder<C, A> {
impl<C: std::fmt::Debug + Clone + 'static, A: std::fmt::Debug + Clone + 'static> std::fmt::Debug
for Builder<C, A>
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.clone().finish().fmt(f)
self.clone().finish().root().fmt(f)
}
}
impl<C: std::fmt::Debug + Clone, A: std::fmt::Debug + Clone> std::fmt::Debug for Tree<C, A> {
impl<C: std::fmt::Debug + Clone, A: std::fmt::Debug + Clone> std::fmt::Debug for Branch<C, A> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
const INDENT: &str = " ";
let mut level = 0;