use serde_derive::Serialize;
use std::path::PathBuf;
use crate::attribute_types::{CanBeEmpty, NameToken, ID};
use crate::element_categories::*;
use crate::extra_attributes::{self, ExtraAttributes};
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,
..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 $($more)* } }
fn extra (& self) -> & extra_attributes::$name { & self.extra }
fn extra_mut(&mut self) -> &mut extra_attributes::$name { &mut self.extra }
}
)}
#[allow(dead_code)]
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().append(&mut children);
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, )* } }
}
)}
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, String)
(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()
}
}