diff --git a/src/iter/ast_node_iter.rs b/src/iter/ast_node_iter.rs index 6c51c11..89d35a8 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_getter_iter; use super::macros::multi_field_iter; use crate::types::AngleLink; use crate::types::BabelCall; @@ -223,12 +224,12 @@ children_iter!( PlainListIter, std::slice::Iter<'r, PlainListItem<'s>> ); -multi_field_iter!( +multi_field_getter_iter!( PlainListItem<'s>, PlainListItemIter, - tag, + get_tag, std::slice::Iter<'r, Object<'s>>, - children, + get_children, std::slice::Iter<'r, Element<'s>> ); children_iter!( diff --git a/src/iter/macros.rs b/src/iter/macros.rs index 3834d1b..466a011 100644 --- a/src/iter/macros.rs +++ b/src/iter/macros.rs @@ -112,3 +112,43 @@ $fieldname: self.$fieldname.iter(), } pub(crate) use multi_field_iter; + +/// Create iterators for ast nodes using getters where it has to iterate over multiple child lists. +macro_rules! multi_field_getter_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_getter_iter; diff --git a/src/types/greater_element.rs b/src/types/greater_element.rs index c63b58c..2fbe2e1 100644 --- a/src/types/greater_element.rs +++ b/src/types/greater_element.rs @@ -1,5 +1,7 @@ use super::element::Element; use super::lesser_element::TableCell; +use super::macros::ref_getter; +use super::macros::simple_getter; use super::Keyword; use super::Object; use super::StandardProperties; @@ -23,14 +25,14 @@ pub type IndentationLevel = u16; #[derive(Debug)] pub struct PlainListItem<'s> { - pub source: &'s str, - pub indentation: IndentationLevel, - pub bullet: &'s str, - pub counter: Option, - pub checkbox: Option<(CheckboxType, &'s str)>, - pub tag: Vec>, - pub pre_blank: PlainListItemPreBlank, - pub children: Vec>, + pub(crate) source: &'s str, + pub(crate) indentation: IndentationLevel, + pub(crate) bullet: &'s str, + pub(crate) counter: Option, + pub(crate) checkbox: Option<(CheckboxType, &'s str)>, + pub(crate) tag: Vec>, + pub(crate) pre_blank: PlainListItemPreBlank, + pub(crate) children: Vec>, } pub type PlainListItemCounter = u16; @@ -157,3 +159,29 @@ impl<'s> StandardProperties<'s> for TableRow<'s> { self.source } } + +impl<'s> PlainListItem<'s> { + simple_getter!(get_indentation_level, indentation, IndentationLevel); + simple_getter!( + /// Get the bullet + /// + /// Example output: "1. " + get_bullet, + bullet, + &'s str + ); + simple_getter!(get_counter, counter, Option); + simple_getter!(get_pre_blank, pre_blank, PlainListItemPreBlank); + ref_getter!(get_tag, tag, Vec>); + ref_getter!(get_children, children, Vec>); + + pub fn get_checkbox(&self) -> Option<&'s str> { + self.checkbox.as_ref().map(|(_, checkbox)| *checkbox) + } + + pub fn get_checkbox_type(&self) -> Option<&CheckboxType> { + self.checkbox + .as_ref() + .map(|(checkbox_type, _)| checkbox_type) + } +} diff --git a/src/types/macros.rs b/src/types/macros.rs new file mode 100644 index 0000000..ce1235a --- /dev/null +++ b/src/types/macros.rs @@ -0,0 +1,21 @@ +// TODO: Would be nice if I didn't have to specify a function name but it looks like concat_idents!() cannot be used to create an ident. +// TODO: Find out if proc macros could do this easier (for example, parsing out the field type) +macro_rules! simple_getter { + ($(#[$meta:meta])* $funcname: ident, $field:ident, $fieldtype:ty) => { + $(#[$meta])* + pub fn $funcname(&self) -> $fieldtype { + self.$field + } + }; +} +pub(crate) use simple_getter; + +macro_rules! ref_getter { + ($(#[$meta:meta])* $funcname: ident, $field:ident, $fieldtype:ty) => { + $(#[$meta])* + pub fn $funcname(&self) -> &$fieldtype { + &self.$field + } + }; +} +pub(crate) use ref_getter; diff --git a/src/types/mod.rs b/src/types/mod.rs index 7976ecd..d0ea1f2 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -3,6 +3,7 @@ mod element; mod get_standard_properties; mod greater_element; mod lesser_element; +mod macros; mod object; mod source; mod standard_properties;