1use std::fmt::{self, Debug, Formatter};
2
3use serde_derive::Serialize;
4
5#[allow(clippy::wildcard_imports)]
6use crate::elements::*;
7
8pub trait HasChildren<C> {
9 fn with_children(children: Vec<C>) -> Self;
10 fn children(&self) -> &Vec<C>;
11 fn children_mut(&mut self) -> &mut Vec<C>;
12 fn append_child<R: Into<C>>(&mut self, child: R) {
13 self.children_mut().push(child.into());
14 }
15 fn append_children<R: Into<C> + Clone>(&mut self, more: &[R]) {
16 let children = self.children_mut();
17 children.reserve(more.len());
18 for child in more {
19 children.push(child.clone().into());
20 }
21 }
22}
23
24macro_rules! impl_into {
25 ([ $( (($subcat:ident :: $entry:ident), $supcat:ident), )+ ]) => {
26 $( impl_into!($subcat::$entry => $supcat); )+
27 };
28 ($subcat:ident :: $entry:ident => $supcat:ident ) => {
29 impl From<$entry> for $supcat {
30 fn from(inner: $entry) -> Self {
31 $supcat::$subcat(Box::new(inner.into()))
32 }
33 }
34 };
35}
36
37macro_rules! synonymous_enum {
38 ( $subcat:ident : $($supcat:ident),+ ; $midcat:ident : $supsupcat:ident { $($entry:ident),+ $(,)* } ) => {
39 synonymous_enum!($subcat : $( $supcat ),+ , $midcat { $($entry,)* });
40 $( impl_into!($midcat::$entry => $supsupcat); )+
41 };
42 ( $subcat:ident : $($supcat:ident),+ { $($entry:ident),+ $(,)* } ) => {
43 synonymous_enum!($subcat { $( $entry, )* });
44 cartesian!(impl_into, [ $( ($subcat::$entry) ),+ ], [ $($supcat),+ ]);
45 };
46 ( $name:ident { $( $entry:ident ),+ $(,)* } ) => {
47 #[derive(PartialEq,Serialize,Clone)]
48 pub enum $name { $(
49 $entry(Box<$entry>),
50 )* }
51
52 impl Debug for $name {
53 fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
54 match *self {
55 $( $name::$entry(ref inner) => inner.fmt(fmt), )*
56 }
57 }
58 }
59
60 $( impl From<$entry> for $name {
61 fn from(inner: $entry) -> Self {
62 $name::$entry(Box::new(inner))
63 }
64 } )*
65 };
66}
67
68synonymous_enum!(StructuralSubElement {
69 Title,
70 Subtitle,
71 Decoration,
72 Docinfo,
73 SubStructure
74});
75synonymous_enum!(SubStructure: StructuralSubElement { Topic, Sidebar, Transition, Section, BodyElement });
76synonymous_enum!(BodyElement: SubTopic, SubSidebar, SubBlockQuote, SubFootnote, SubFigure; SubStructure: StructuralSubElement {
77 Paragraph, LiteralBlock, DoctestBlock, MathBlock, Rubric, SubstitutionDefinition, Comment, Pending, Target, Raw, Image,
79 Compound, Container,
81 BulletList, EnumeratedList, DefinitionList, FieldList, OptionList,
82 LineBlock, BlockQuote, Admonition, Attention, Hint, Note, Caution, Danger, Error, Important, Tip, Warning, Footnote, Citation, SystemMessage, Figure, Table
83});
84
85impl<'a> TryFrom<&'a StructuralSubElement> for &'a BodyElement {
86 type Error = ();
87
88 fn try_from(value: &'a StructuralSubElement) -> Result<Self, ()> {
89 match value {
90 StructuralSubElement::SubStructure(s) => s.as_ref().try_into(),
91 _ => Err(()),
92 }
93 }
94}
95
96impl<'a> TryFrom<&'a SubStructure> for &'a BodyElement {
97 type Error = ();
98
99 fn try_from(value: &'a SubStructure) -> Result<Self, ()> {
100 match value {
101 SubStructure::BodyElement(s) => Ok(s.as_ref()),
102 _ => Err(()),
103 }
104 }
105}
106
107synonymous_enum!(BibliographicElement {
108 Authors,
109 Author,
111 Organization,
112 Address,
113 Contact,
114 Version,
116 Revision,
117 Status,
118 Date,
119 Copyright,
120 Field
121});
122
123synonymous_enum!(TextOrInlineElement {
124 String,
125 Emphasis,
126 Strong,
127 Literal,
128 Reference,
129 FootnoteReference,
130 CitationReference,
131 SubstitutionReference,
132 TitleReference,
133 Abbreviation,
134 Acronym,
135 Superscript,
136 Subscript,
137 Inline,
138 Problematic,
139 Generated,
140 Math,
141 TargetInline,
143 RawInline,
144 ImageInline
145});
146
147synonymous_enum!(AuthorInfo {
152 Author,
153 Organization,
154 Address,
155 Contact
156});
157synonymous_enum!(DecorationElement { Header, Footer });
158synonymous_enum!(SubTopic { Title, BodyElement });
159synonymous_enum!(SubSidebar {
160 Topic,
161 Title,
162 Subtitle,
163 BodyElement
164});
165synonymous_enum!(SubDLItem {
166 Term,
167 Classifier,
168 Definition
169});
170synonymous_enum!(SubField {
171 FieldName,
172 FieldBody
173});
174synonymous_enum!(SubOptionListItem {
175 OptionGroup,
176 Description
177});
178synonymous_enum!(SubOption {
179 OptionString,
180 OptionArgument
181});
182synonymous_enum!(SubLineBlock { LineBlock, Line });
183synonymous_enum!(SubBlockQuote {
184 Attribution,
185 BodyElement
186});
187synonymous_enum!(SubFootnote { Label, BodyElement });
188synonymous_enum!(SubFigure {
189 Caption,
190 Legend,
191 BodyElement
192});
193synonymous_enum!(SubTable { Title, TableGroup });
194synonymous_enum!(SubTableGroup {
195 TableColspec,
196 TableHead,
197 TableBody
198});
199
200impl From<SubTopic> for SubSidebar {
202 fn from(inner: SubTopic) -> Self {
203 match inner {
204 SubTopic::Title(e) => (*e).into(),
205 SubTopic::BodyElement(e) => (*e).into(),
206 }
207 }
208}
209
210impl From<SubTopic> for StructuralSubElement {
211 fn from(inner: SubTopic) -> Self {
212 match inner {
213 SubTopic::Title(e) => (*e).into(),
214 SubTopic::BodyElement(e) => (*e).into(),
215 }
216 }
217}
218
219impl From<SubSidebar> for StructuralSubElement {
220 fn from(inner: SubSidebar) -> Self {
221 match inner {
222 SubSidebar::Topic(e) => (*e).into(),
223 SubSidebar::Title(e) => (*e).into(),
224 SubSidebar::Subtitle(e) => (*e).into(),
225 SubSidebar::BodyElement(e) => (*e).into(),
226 }
227 }
228}
229
230impl From<AuthorInfo> for BibliographicElement {
231 fn from(inner: AuthorInfo) -> Self {
232 match inner {
233 AuthorInfo::Author(e) => (*e).into(),
234 AuthorInfo::Organization(e) => (*e).into(),
235 AuthorInfo::Address(e) => (*e).into(),
236 AuthorInfo::Contact(e) => (*e).into(),
237 }
238 }
239}
240
241#[cfg(test)]
242mod conversion_tests {
243 use super::*;
244 use std::default::Default;
245
246 #[test]
247 fn basic() {
248 let _: BodyElement = Paragraph::default().into();
249 }
250
251 #[test]
252 fn more() {
253 let _: SubStructure = Paragraph::default().into();
254 }
255
256 #[test]
257 fn even_more() {
258 let _: StructuralSubElement = Paragraph::default().into();
259 }
260
261 #[test]
262 fn super_() {
263 let be: BodyElement = Paragraph::default().into();
264 let _: StructuralSubElement = be.into();
265 }
266}