use serde_derive::Serialize; use crate::target; use super::attribute_types::{CanBeEmpty,ID,NameToken}; use super::extra_attributes::{self,ExtraAttributes}; use super::element_categories::*; //-----------------\\ //Element hierarchy\\ //-----------------\\ pub trait Element { /// A list containing one or more unique identifier keys fn ids (& self) -> & Vec; fn ids_mut(&mut self) -> &mut Vec; /// 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; fn names_mut(&mut self) -> &mut Vec; fn source (& self) -> & Option; fn source_mut(&mut self) -> &mut Option; fn classes (& self) -> & Vec; fn classes_mut(&mut self) -> &mut Vec; } #[derive(Debug,Default,PartialEq,Serialize,Clone)] pub struct CommonAttributes { #[serde(skip_serializing_if = "CanBeEmpty::is_empty")] ids: Vec, #[serde(skip_serializing_if = "CanBeEmpty::is_empty")] names: Vec, #[serde(skip_serializing_if = "CanBeEmpty::is_empty")] source: Option, #[serde(skip_serializing_if = "CanBeEmpty::is_empty")] classes: Vec, //TODO: dupnames } //----\\ //impl\\ //----\\ macro_rules! impl_element { ($name:ident) => ( impl Element for $name { fn ids (& self) -> & Vec { & self.common.ids } fn ids_mut(&mut self) -> &mut Vec { &mut self.common.ids } fn names (& self) -> & Vec { & self.common.names } fn names_mut(&mut self) -> &mut Vec { &mut self.common.names } fn source (& self) -> & Option { & self.common.source } fn source_mut(&mut self) -> &mut Option { &mut self.common.source } fn classes (& self) -> & Vec { & self.common.classes } fn classes_mut(&mut self) -> &mut Vec { &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 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 } } )} 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 } 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() } }