use std::fmt::{self, Debug, Formatter};
use serde_derive::Serialize;
use crate::elements::*;
pub trait HasChildren<C> {
fn with_children(children: Vec<C>) -> Self;
fn children(&self) -> &Vec<C>;
fn children_mut(&mut self) -> &mut Vec<C>;
fn append_child<R: Into<C>>(&mut self, child: R) {
self.children_mut().push(child.into());
}
fn append_children<R: Into<C> + Clone>(&mut self, more: &[R]) {
let children = self.children_mut();
children.reserve(more.len());
for child in more {
children.push(child.clone().into());
}
}
}
macro_rules! impl_into {
([ $( (($subcat:ident :: $entry:ident), $supcat:ident), )+ ]) => {
$( impl_into!($subcat::$entry => $supcat); )+
};
($subcat:ident :: $entry:ident => $supcat:ident ) => {
impl From<$entry> for $supcat {
fn from(inner: $entry) -> Self {
$supcat::$subcat(Box::new(inner.into()))
}
}
};
}
macro_rules! synonymous_enum {
( $subcat:ident : $($supcat:ident),+ ; $midcat:ident : $supsupcat:ident { $($entry:ident),+ $(,)* } ) => {
synonymous_enum!($subcat : $( $supcat ),+ , $midcat { $($entry,)* });
$( impl_into!($midcat::$entry => $supsupcat); )+
};
( $subcat:ident : $($supcat:ident),+ { $($entry:ident),+ $(,)* } ) => {
synonymous_enum!($subcat { $( $entry, )* });
cartesian!(impl_into, [ $( ($subcat::$entry) ),+ ], [ $($supcat),+ ]);
};
( $name:ident { $( $entry:ident ),+ $(,)* } ) => {
#[derive(PartialEq,Serialize,Clone)]
pub enum $name { $(
$entry(Box<$entry>),
)* }
impl Debug for $name {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
match *self {
$( $name::$entry(ref inner) => inner.fmt(fmt), )*
}
}
}
$( impl From<$entry> for $name {
fn from(inner: $entry) -> Self {
$name::$entry(Box::new(inner))
}
} )*
};
}
synonymous_enum!(StructuralSubElement {
Title,
Subtitle,
Decoration,
Docinfo,
SubStructure
});
synonymous_enum!(SubStructure: StructuralSubElement { Topic, Sidebar, Transition, Section, BodyElement });
synonymous_enum!(BodyElement: SubTopic, SubSidebar, SubBlockQuote, SubFootnote, SubFigure; SubStructure: StructuralSubElement {
Paragraph, LiteralBlock, DoctestBlock, MathBlock, Rubric, SubstitutionDefinition, Comment, Pending, Target, Raw, Image,
Compound, Container,
BulletList, EnumeratedList, DefinitionList, FieldList, OptionList,
LineBlock, BlockQuote, Admonition, Attention, Hint, Note, Caution, Danger, Error, Important, Tip, Warning, Footnote, Citation, SystemMessage, Figure, Table
});
synonymous_enum!(BibliographicElement {
Author,
Authors,
Organization,
Address,
Contact,
Version,
Revision,
Status,
Date,
Copyright,
Field
});
synonymous_enum!(TextOrInlineElement {
String,
Emphasis,
Strong,
Literal,
Reference,
FootnoteReference,
CitationReference,
SubstitutionReference,
TitleReference,
Abbreviation,
Acronym,
Superscript,
Subscript,
Inline,
Problematic,
Generated,
Math,
TargetInline,
RawInline,
ImageInline
});
synonymous_enum!(AuthorInfo {
Author,
Organization,
Address,
Contact
});
synonymous_enum!(DecorationElement { Header, Footer });
synonymous_enum!(SubTopic { Title, BodyElement });
synonymous_enum!(SubSidebar {
Topic,
Title,
Subtitle,
BodyElement
});
synonymous_enum!(SubDLItem {
Term,
Classifier,
Definition
});
synonymous_enum!(SubField {
FieldName,
FieldBody
});
synonymous_enum!(SubOptionListItem {
OptionGroup,
Description
});
synonymous_enum!(SubOption {
OptionString,
OptionArgument
});
synonymous_enum!(SubLineBlock { LineBlock, Line });
synonymous_enum!(SubBlockQuote {
Attribution,
BodyElement
});
synonymous_enum!(SubFootnote { Label, BodyElement });
synonymous_enum!(SubFigure {
Caption,
Legend,
BodyElement
});
synonymous_enum!(SubTable { Title, TableGroup });
synonymous_enum!(SubTableGroup {
TableColspec,
TableHead,
TableBody
});
#[cfg(test)]
mod conversion_tests {
use super::*;
use std::default::Default;
#[test]
fn basic() {
let _: BodyElement = Paragraph::default().into();
}
#[test]
fn more() {
let _: SubStructure = Paragraph::default().into();
}
#[test]
fn even_more() {
let _: StructuralSubElement = Paragraph::default().into();
}
#[test]
fn super_() {
let be: BodyElement = Paragraph::default().into();
let _: StructuralSubElement = be.into();
}
}