From 4359fc92667109e83573730a9c09950a11b3ded0 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Wed, 27 Sep 2023 15:47:01 -0400 Subject: [PATCH] Introduce a macro for empty iterators. --- src/iter/ast_node_iter.rs | 19 ++++++++++++++----- src/iter/macros.rs | 35 +++++++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/iter/ast_node_iter.rs b/src/iter/ast_node_iter.rs index 19b85c1..39d5b58 100644 --- a/src/iter/ast_node_iter.rs +++ b/src/iter/ast_node_iter.rs @@ -1,14 +1,21 @@ use std::marker::PhantomData; use super::ast_node::AstNode; -use super::macros::simple_iter; +use super::macros::children_iter; +use super::macros::empty_iter; use crate::types::Bold; use crate::types::Code; use crate::types::Italic; use crate::types::Object; use crate::types::StrikeThrough; use crate::types::Underline; +use crate::types::Verbatim; +/// Iterator over the AST nodes contained within the starting node. +/// +/// This only iterates over the children, not the starting node itself. So an AstNodeIter::PlainList would only return PlainListItems, not the PlainList. +/// +/// This only iterates over AST nodes, so an AstNodeIter::Heading would iterate over both the title and section contents, but it would not iterate over simple strings like the TODO keyword or priority. pub enum AstNodeIter<'r, 's> { // Document Nodes // Document(DocumentIter<'r, 's>), @@ -43,7 +50,7 @@ pub enum AstNodeIter<'r, 's> { Underline(UnderlineIter<'r, 's>), StrikeThrough(StrikeThroughIter<'r, 's>), Code(CodeIter<'r, 's>), - // Verbatim(VerbatimIter<'r, 's>), + Verbatim(VerbatimIter<'r, 's>), // PlainText(PlainTextIter<'r, 's>), // RegularLink(RegularLinkIter<'r, 's>), // RadioLink(RadioLinkIter<'r, 's>), @@ -91,13 +98,13 @@ impl<'r, 's> IntoIterator for &'r Bold<'s> { } } -simple_iter!(Italic<'s>, ItalicIter, std::slice::Iter<'r, Object<'s>>); -simple_iter!( +children_iter!(Italic<'s>, ItalicIter, std::slice::Iter<'r, Object<'s>>); +children_iter!( Underline<'s>, UnderlineIter, std::slice::Iter<'r, Object<'s>> ); -simple_iter!( +children_iter!( StrikeThrough<'s>, StrikeThroughIter, std::slice::Iter<'r, Object<'s>> @@ -126,3 +133,5 @@ impl<'r, 's> IntoIterator for &'r Code<'s> { } } } + +empty_iter!(Verbatim<'s>, VerbatimIter); diff --git a/src/iter/macros.rs b/src/iter/macros.rs index acb0f40..07b36fe 100644 --- a/src/iter/macros.rs +++ b/src/iter/macros.rs @@ -1,5 +1,5 @@ /// Create iterators for ast nodes where it only has to iterate over children -macro_rules! simple_iter { +macro_rules! children_iter { ($astnodetype:ty, $itertype:ident, $innertype:ty) => { pub struct $itertype<'r, 's> { next: $innertype, @@ -27,4 +27,35 @@ macro_rules! simple_iter { }; } -pub(crate) use simple_iter; +pub(crate) use children_iter; + +/// Create iterators for ast nodes that do not contain any ast node children. +macro_rules! empty_iter { + ($astnodetype:ty, $itertype:ident) => { + pub struct $itertype<'r, 's> { + phantom: PhantomData<&'r $astnodetype>, + } + + impl<'r, 's> Iterator for $itertype<'r, 's> { + type Item = AstNode<'r, 's>; + + fn next(&mut self) -> Option { + None + } + } + + impl<'r, 's> IntoIterator for &'r $astnodetype { + type Item = AstNode<'r, 's>; + + type IntoIter = $itertype<'r, 's>; + + fn into_iter(self) -> Self::IntoIter { + $itertype { + phantom: PhantomData, + } + } + } + }; +} + +pub(crate) use empty_iter;