diff options
Diffstat (limited to 'document_tree/src/elements.rs')
| -rw-r--r-- | document_tree/src/elements.rs | 288 | 
1 files changed, 288 insertions, 0 deletions
| diff --git a/document_tree/src/elements.rs b/document_tree/src/elements.rs new file mode 100644 index 0000000..26bccf6 --- /dev/null +++ b/document_tree/src/elements.rs @@ -0,0 +1,288 @@ +use std::path::PathBuf; +use serde_derive::Serialize; + +use crate::attribute_types::{CanBeEmpty,ID,NameToken}; +use crate::extra_attributes::{self,ExtraAttributes}; +use crate::element_categories::*; + + +//-----------------\\ +//Element hierarchy\\ +//-----------------\\ + +pub trait Element { +	/// A list containing one or more unique identifier keys +	fn     ids    (&    self) -> &    Vec<ID>; +	fn     ids_mut(&mut self) -> &mut Vec<ID>; +	/// a list containing the names of an element, typically originating from the element's title or content. +	/// Each name in names must be unique; if there are name conflicts (two or more elements want to the same name), +	/// the contents will be transferred to the dupnames attribute on the duplicate elements. +	/// An element may have at most one of the names or dupnames attributes, but not both. +	fn   names    (&    self) -> &    Vec<NameToken>; +	fn   names_mut(&mut self) -> &mut Vec<NameToken>; +	fn  source    (&    self) -> &    Option<PathBuf>; +	fn  source_mut(&mut self) -> &mut Option<PathBuf>; +	fn classes    (&    self) -> &    Vec<String>; +	fn classes_mut(&mut self) -> &mut Vec<String>; +} + +#[derive(Debug,Default,PartialEq,Serialize,Clone)] +pub struct CommonAttributes { +	#[serde(skip_serializing_if = "CanBeEmpty::is_empty")] +	ids: Vec<ID>, +	#[serde(skip_serializing_if = "CanBeEmpty::is_empty")] +	names: Vec<NameToken>, +	#[serde(skip_serializing_if = "CanBeEmpty::is_empty")] +	source: Option<PathBuf>, +	#[serde(skip_serializing_if = "CanBeEmpty::is_empty")] +	classes: Vec<String>, +	//TODO: dupnames +} + +//----\\ +//impl\\ +//----\\ + +macro_rules! impl_element { ($name:ident) => ( +	impl Element for $name { +		fn     ids    (&    self) -> &    Vec<ID>         { &    self.common.ids     } +		fn     ids_mut(&mut self) -> &mut Vec<ID>         { &mut self.common.ids     } +		fn   names    (&    self) -> &    Vec<NameToken>  { &    self.common.names   } +		fn   names_mut(&mut self) -> &mut Vec<NameToken>  { &mut self.common.names   } +		fn  source    (&    self) -> &    Option<PathBuf> { &    self.common.source  } +		fn  source_mut(&mut self) -> &mut Option<PathBuf> { &mut self.common.source  } +		fn classes    (&    self) -> &    Vec<String> { &    self.common.classes } +		fn classes_mut(&mut self) -> &mut Vec<String> { &mut self.common.classes } +	} +)} + +macro_rules! impl_children { ($name:ident, $childtype:ident) => ( +	impl HasChildren<$childtype> for $name { +		#[allow(clippy::needless_update)] +		fn with_children(children: Vec<$childtype>) -> $name { $name { children: children, ..Default::default() } } +		fn children    (&    self) -> &    Vec<$childtype> { &    self.children } +		fn children_mut(&mut self) -> &mut Vec<$childtype> { &mut self.children } +	} +)} + +macro_rules! impl_extra { ($name:ident $($more:tt)*) => ( +	impl ExtraAttributes<extra_attributes::$name> for $name { +		#[allow(clippy::needless_update)] +		fn with_extra(extra: extra_attributes::$name) -> $name { $name { common: Default::default(), extra: extra $($more)* } } +		fn extra    (&    self) -> &    extra_attributes::$name { &    self.extra } +		fn extra_mut(&mut self) -> &mut extra_attributes::$name { &mut self.extra } +	} +)} + +trait HasExtraAndChildren<C, A> { +	fn with_extra_and_children(extra: A, children: Vec<C>) -> Self; +} + +impl<T, C, A> HasExtraAndChildren<C, A> for T where T: HasChildren<C> + ExtraAttributes<A> { +	#[allow(clippy::needless_update)] +	fn with_extra_and_children(extra: A, mut children: Vec<C>) -> Self { +		let mut r = Self::with_extra(extra); +		r.children_mut().extend(children.drain(..)); +		r +	} +} + +macro_rules! impl_new {( +	$(#[$attr:meta])* +	pub struct $name:ident { $( +		$(#[$fattr:meta])* +		$field:ident : $typ:path +	),* $(,)* } +) => ( +	$(#[$attr])* +	#[derive(Debug,PartialEq,Serialize,Clone)] +	pub struct $name { $(  +		$(#[$fattr])* $field: $typ, +	)* } +	impl $name { +		pub fn new( $( $field: $typ, )* ) -> $name { $name { $( $field: $field, )* } } +	} +)} + +macro_rules! impl_elem { +	($name:ident) => { +		impl_new!(#[derive(Default)] pub struct $name { +			#[serde(flatten)] common: CommonAttributes, +		}); +		impl_element!($name); +	}; +	($name:ident; +) => { +		impl_new!(#[derive(Default)] pub struct $name { +			#[serde(flatten)] common: CommonAttributes, +			#[serde(flatten)] extra: extra_attributes::$name, +		}); +		impl_element!($name); impl_extra!($name, ..Default::default()); +	}; +	($name:ident; *) => { //same as above with no default +		impl_new!(pub struct $name { +			#[serde(flatten)] common: CommonAttributes, +			#[serde(flatten)] extra: extra_attributes::$name +		}); +		impl_element!($name); impl_extra!($name); +	}; +	($name:ident, $childtype:ident) => { +		impl_new!(#[derive(Default)] pub struct $name { +			#[serde(flatten)] common: CommonAttributes, +			children: Vec<$childtype>, +		}); +		impl_element!($name); impl_children!($name, $childtype); +	}; +	($name:ident, $childtype:ident; +) => { +		impl_new!(#[derive(Default)] pub struct $name { +			#[serde(flatten)] common: CommonAttributes, +			#[serde(flatten)] extra: extra_attributes::$name, +			children: Vec<$childtype>, +		}); +		impl_element!($name); impl_extra!($name, ..Default::default()); impl_children!($name, $childtype); +	}; +} + +macro_rules! impl_elems { ( $( ($($args:tt)*) )* ) => ( +	$( impl_elem!($($args)*); )* +)} + + +#[derive(Default,Debug,Serialize)] +pub struct Document { children: Vec<StructuralSubElement> } +impl_children!(Document, StructuralSubElement); + +impl_elems!( +	//structual elements +	(Section, StructuralSubElement) +	(Topic,   SubTopic) +	(Sidebar, SubSidebar) +	 +	//structural subelements +	(Title,      TextOrInlineElement) +	(Subtitle,   TextOrInlineElement) +	(Decoration, DecorationElement) +	(Docinfo,    BibliographicElement) +	(Transition) +	 +	//bibliographic elements +	(Author,       TextOrInlineElement) +	(Authors,      AuthorInfo) +	(Organization, TextOrInlineElement) +	(Address,      TextOrInlineElement; +) +	(Contact,      TextOrInlineElement) +	(Version,      TextOrInlineElement) +	(Revision,     TextOrInlineElement) +	(Status,       TextOrInlineElement) +	(Date,         TextOrInlineElement) +	(Copyright,    TextOrInlineElement) +	(Field,        SubField) +	 +	//decoration elements +	(Header, BodyElement) +	(Footer, BodyElement) +	 +	//simple body elements +	(Paragraph,              TextOrInlineElement) +	(LiteralBlock,           TextOrInlineElement; +) +	(DoctestBlock,           TextOrInlineElement; +) +	(MathBlock,              String) +	(Rubric,                 TextOrInlineElement) +	(SubstitutionDefinition, TextOrInlineElement; +) +	(Comment,                TextOrInlineElement; +) +	(Pending) +	(Target; +) +	(Raw, String; +) +	(Image; *) +	 +	//compound body elements +	(Compound,  BodyElement) +	(Container, BodyElement) +	 +	(BulletList,     ListItem; +) +	(EnumeratedList, ListItem; +) +	(DefinitionList, DefinitionListItem) +	(FieldList,      Field) +	(OptionList,     OptionListItem) +	 +	(LineBlock,     SubLineBlock) +	(BlockQuote,    SubBlockQuote) +	(Admonition,    SubTopic) +	(Attention,     BodyElement) +	(Hint,          BodyElement) +	(Note,          BodyElement) +	(Caution,       BodyElement) +	(Danger,        BodyElement) +	(Error,         BodyElement) +	(Important,     BodyElement) +	(Tip,           BodyElement) +	(Warning,       BodyElement) +	(Footnote,      SubFootnote; +) +	(Citation,      SubFootnote; +) +	(SystemMessage, BodyElement; +) +	(Figure,        SubFigure;   +) +	(Table,         SubTable;    +) + +	//table elements +	(TableGroup, SubTableGroup; +) +	(TableHead,  TableRow;      +) +	(TableBody,  TableRow;      +) +	(TableRow,   TableEntry;    +) +	(TableEntry, BodyElement;   +) +	(TableColspec; +) +	 +	//body sub elements +	(ListItem, BodyElement) +	 +	(DefinitionListItem, SubDLItem) +	(Term,               TextOrInlineElement) +	(Classifier,         TextOrInlineElement) +	(Definition,         BodyElement) +	 +	(FieldName, TextOrInlineElement) +	(FieldBody, BodyElement) +	 +	(OptionListItem, SubOptionListItem) +	(OptionGroup,    Option_) +	(Description,    BodyElement) +	(Option_,        SubOption) +	(OptionString,   String) +	(OptionArgument, String; +) +	 +	(Line,        TextOrInlineElement) +	(Attribution, TextOrInlineElement) +	(Label,       TextOrInlineElement) +	 +	(Caption, TextOrInlineElement) +	(Legend,  BodyElement) +	 +	//inline elements +	(Emphasis,              TextOrInlineElement) +	(Literal,               TextOrInlineElement) +	(Reference,             TextOrInlineElement; +) +	(Strong,                TextOrInlineElement) +	(FootnoteReference,     TextOrInlineElement; +) +	(CitationReference,     TextOrInlineElement; +) +	(SubstitutionReference, TextOrInlineElement; +) +	(TitleReference,        TextOrInlineElement) +	(Abbreviation,          TextOrInlineElement) +	(Acronym,               TextOrInlineElement) +	(Superscript,           TextOrInlineElement) +	(Subscript,             TextOrInlineElement) +	(Inline,                TextOrInlineElement) +	(Problematic,           TextOrInlineElement; +) +	(Generated,             TextOrInlineElement) +	(Math,                  String) +	 +	//also have non-inline versions. Inline image is no figure child, inline target has content +	(TargetInline, String; +) +	(RawInline,    String; +) +	(ImageInline; *) +	 +	//text element = String +); + +impl<'a> From<&'a str> for TextOrInlineElement { +	fn from(s: &'a str) -> Self { +		s.to_owned().into() +	} +} | 
