From dae10c2eef91be206908ae5951797cb2253a395e Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Fri, 29 Sep 2023 20:17:23 -0400 Subject: [PATCH 1/2] Initial work for exposing getters and hiding the fields of the ast nodes. Ultimately this is about semver and exposing a stable interface while allowing the internal representation to change. The fields are still pub(crate) to make constructing the types easier inside this crate, which should be fine because we can refactor the code inside this crate whenever the internal structure changes. --- src/iter/ast_node_iter.rs | 7 +++--- src/iter/macros.rs | 40 ++++++++++++++++++++++++++++++++ src/types/greater_element.rs | 44 +++++++++++++++++++++++++++++------- src/types/macros.rs | 21 +++++++++++++++++ src/types/mod.rs | 1 + 5 files changed, 102 insertions(+), 11 deletions(-) create mode 100644 src/types/macros.rs 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; From 5d1582be4d33f9eff6e718d1b6b68c2889b9725b Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Fri, 29 Sep 2023 20:38:04 -0400 Subject: [PATCH 2/2] Remove multi_field_getter_iter. This was written because I originally intended to make the fields of the ast node types entirely private, but that made constructing them tedious so they are pub(crate) which coincidentally also allows them to be used by the iterator. --- src/iter/ast_node_iter.rs | 7 +++---- src/iter/macros.rs | 40 --------------------------------------- 2 files changed, 3 insertions(+), 44 deletions(-) diff --git a/src/iter/ast_node_iter.rs b/src/iter/ast_node_iter.rs index 89d35a8..6c51c11 100644 --- a/src/iter/ast_node_iter.rs +++ b/src/iter/ast_node_iter.rs @@ -3,7 +3,6 @@ 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; @@ -224,12 +223,12 @@ children_iter!( PlainListIter, std::slice::Iter<'r, PlainListItem<'s>> ); -multi_field_getter_iter!( +multi_field_iter!( PlainListItem<'s>, PlainListItemIter, - get_tag, + tag, std::slice::Iter<'r, Object<'s>>, - get_children, + children, std::slice::Iter<'r, Element<'s>> ); children_iter!( diff --git a/src/iter/macros.rs b/src/iter/macros.rs index 466a011..3834d1b 100644 --- a/src/iter/macros.rs +++ b/src/iter/macros.rs @@ -112,43 +112,3 @@ $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;