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::*;
pub trait Element {
fn ids (& self) -> & Vec<ID>;
fn ids_mut(&mut self) -> &mut Vec<ID>;
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>,
}
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; *) => {
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!(
(Section, StructuralSubElement)
(Topic, SubTopic)
(Sidebar, SubSidebar)
(Title, TextOrInlineElement)
(Subtitle, TextOrInlineElement)
(Decoration, DecorationElement)
(Docinfo, BibliographicElement)
(Transition)
(Author, TextOrInlineElement)
(Authors, AuthorInfo)
(Organization, TextOrInlineElement)
(Address, TextOrInlineElement; +)
(Contact, TextOrInlineElement)
(Version, TextOrInlineElement)
(Revision, TextOrInlineElement)
(Status, TextOrInlineElement)
(Date, TextOrInlineElement)
(Copyright, TextOrInlineElement)
(Field, SubField)
(Header, BodyElement)
(Footer, BodyElement)
(Paragraph, TextOrInlineElement)
(LiteralBlock, TextOrInlineElement; +)
(DoctestBlock, TextOrInlineElement; +)
(MathBlock, String)
(Rubric, TextOrInlineElement)
(SubstitutionDefinition, TextOrInlineElement; +)
(Comment, TextOrInlineElement; +)
(Pending)
(Target; +)
(Raw, String; +)
(Image; *)
(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; +)
(TableGroup, SubTableGroup; +)
(TableHead, TableRow; +)
(TableBody, TableRow; +)
(TableRow, TableEntry; +)
(TableEntry, BodyElement; +)
(TableColspec; +)
(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)
(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)
(TargetInline, String; +)
(RawInline, String; +)
(ImageInline; *)
);
impl<'a> From<&'a str> for TextOrInlineElement {
fn from(s: &'a str) -> Self {
s.to_owned().into()
}
}