From 32a7ce3f361c7ae00d950b42921790eb36de69d5 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Wed, 27 Sep 2023 18:27:52 -0400 Subject: [PATCH] Implement a macro for iterators with multiple fields. --- src/iter/ast_node_iter.rs | 11 +++++++++++ src/iter/macros.rs | 40 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/iter/ast_node_iter.rs b/src/iter/ast_node_iter.rs index aa7adcd..1c08490 100644 --- a/src/iter/ast_node_iter.rs +++ b/src/iter/ast_node_iter.rs @@ -3,6 +3,7 @@ use std::marker::PhantomData; use super::ast_node::AstNode; use super::macros::children_iter; use super::macros::empty_iter; +use super::macros::multi_field_iter; use crate::types::Bold; use crate::types::Code; use crate::types::Document; @@ -35,6 +36,7 @@ pub enum AstNodeIter<'r, 's> { // Elements Paragraph(ParagraphIter<'r, 's>), PlainList(PlainListIter<'r, 's>), + PlainListItem(PlainListItemIter<'r, 's>), // GreaterBlock(GreaterBlockIter<'r, 's>), // DynamicBlock(DynamicBlockIter<'r, 's>), // FootnoteDefinition(FootnoteDefinitionIter<'r, 's>), @@ -154,6 +156,15 @@ children_iter!( PlainListIter, std::slice::Iter<'r, PlainListItem<'s>> ); + +multi_field_iter!( + PlainListItem<'s>, + PlainListItemIter, + tag, + std::slice::Iter<'r, Object<'s>>, + children, + std::slice::Iter<'r, Element<'s>> +); children_iter!(Bold<'s>, BoldIter, std::slice::Iter<'r, Object<'s>>); children_iter!(Italic<'s>, ItalicIter, std::slice::Iter<'r, Object<'s>>); children_iter!( diff --git a/src/iter/macros.rs b/src/iter/macros.rs index c6f1901..3834d1b 100644 --- a/src/iter/macros.rs +++ b/src/iter/macros.rs @@ -72,3 +72,43 @@ macro_rules! empty_iter { } pub(crate) use empty_iter; + +/// Create iterators for ast nodes where it has to iterate over multiple child lists. +macro_rules! multi_field_iter { + ($astnodetype:ty, $itertype:ident, $firstfieldname: ident, $firstinnertype:ty, $($fieldname: ident, $innertype:ty),*) => { + pub struct $itertype<'r, 's> { + $firstfieldname: $firstinnertype, + $( +$fieldname: $innertype, +),* + } + + impl<'r, 's> Iterator for $itertype<'r, 's> { + type Item = AstNode<'r, 's>; + + fn next(&mut self) -> Option { + self.$firstfieldname.next().map(Into::::into) + $( +.or_else(|| self.$fieldname.next().map(Into::::into)) +),* + } + } + + impl<'r, 's> IntoIterator for &'r $astnodetype { + type Item = AstNode<'r, 's>; + + type IntoIter = $itertype<'r, 's>; + + fn into_iter(self) -> Self::IntoIter { + $itertype { + $firstfieldname: self.$firstfieldname.iter(), + $( +$fieldname: self.$fieldname.iter(), +),* + } + } + } + }; +} + +pub(crate) use multi_field_iter;