document_tree/
elements.rs

1use schemars::JsonSchema;
2use serde_derive::Serialize;
3use std::path::PathBuf;
4
5use crate::attribute_types::{CanBeEmpty, ID, NameToken};
6#[allow(clippy::wildcard_imports)]
7use crate::element_categories::*;
8use crate::extra_attributes::{self, ExtraAttributes};
9
10//-----------------\\
11//Element hierarchy\\
12//-----------------\\
13
14pub trait Element {
15    /// A list containing one or more unique identifier keys
16    fn ids(&self) -> &Vec<ID>;
17    fn ids_mut(&mut self) -> &mut Vec<ID>;
18    /// a list containing the names of an element, typically originating from the element's title or content.
19    /// Each name in names must be unique; if there are name conflicts (two or more elements want to the same name),
20    /// the contents will be transferred to the dupnames attribute on the duplicate elements.
21    /// An element may have at most one of the names or dupnames attributes, but not both.
22    fn names(&self) -> &Vec<NameToken>;
23    fn names_mut(&mut self) -> &mut Vec<NameToken>;
24    fn source(&self) -> &Option<PathBuf>;
25    fn source_mut(&mut self) -> &mut Option<PathBuf>;
26    fn classes(&self) -> &Vec<String>;
27    fn classes_mut(&mut self) -> &mut Vec<String>;
28}
29
30#[derive(Clone, Debug, Default, PartialEq, Serialize, JsonSchema)]
31pub struct CommonAttributes {
32    #[serde(default, skip_serializing_if = "CanBeEmpty::is_empty")]
33    ids: Vec<ID>,
34    #[serde(default, skip_serializing_if = "CanBeEmpty::is_empty")]
35    names: Vec<NameToken>,
36    #[serde(default, skip_serializing_if = "CanBeEmpty::is_empty")]
37    source: Option<PathBuf>,
38    #[serde(default, skip_serializing_if = "CanBeEmpty::is_empty")]
39    classes: Vec<String>,
40    //TODO: dupnames
41}
42
43//----\\
44//impl\\
45//----\\
46
47macro_rules! impl_element {
48    ($name:ident) => {
49        impl Element for $name {
50            fn ids(&self) -> &Vec<ID> {
51                &self.common.ids
52            }
53            fn ids_mut(&mut self) -> &mut Vec<ID> {
54                &mut self.common.ids
55            }
56            fn names(&self) -> &Vec<NameToken> {
57                &self.common.names
58            }
59            fn names_mut(&mut self) -> &mut Vec<NameToken> {
60                &mut self.common.names
61            }
62            fn source(&self) -> &Option<PathBuf> {
63                &self.common.source
64            }
65            fn source_mut(&mut self) -> &mut Option<PathBuf> {
66                &mut self.common.source
67            }
68            fn classes(&self) -> &Vec<String> {
69                &self.common.classes
70            }
71            fn classes_mut(&mut self) -> &mut Vec<String> {
72                &mut self.common.classes
73            }
74        }
75    };
76}
77
78macro_rules! impl_children {
79    ($name:ident, $childtype:ident) => {
80        impl HasChildren<$childtype> for $name {
81            #[allow(clippy::needless_update)]
82            fn with_children(children: Vec<$childtype>) -> $name {
83                $name {
84                    children,
85                    ..Default::default()
86                }
87            }
88            fn children(&self) -> &Vec<$childtype> {
89                &self.children
90            }
91            fn children_mut(&mut self) -> &mut Vec<$childtype> {
92                &mut self.children
93            }
94        }
95    };
96}
97
98macro_rules! impl_extra { ($name:ident $($more:tt)*) => (
99    impl ExtraAttributes<extra_attributes::$name> for $name {
100        #[allow(clippy::needless_update)]
101        fn with_extra(extra: extra_attributes::$name) -> $name { $name { common: Default::default(), extra $($more)* } }
102        fn extra    (&    self) -> &    extra_attributes::$name { &    self.extra }
103        fn extra_mut(&mut self) -> &mut extra_attributes::$name { &mut self.extra }
104    }
105)}
106
107#[allow(dead_code)]
108trait HasExtraAndChildren<C, A> {
109    fn with_extra_and_children(extra: A, children: Vec<C>) -> Self;
110}
111
112impl<T, C, A> HasExtraAndChildren<C, A> for T
113where
114    T: HasChildren<C> + ExtraAttributes<A>,
115{
116    #[allow(clippy::needless_update)]
117    fn with_extra_and_children(extra: A, mut children: Vec<C>) -> Self {
118        let mut r = Self::with_extra(extra);
119        r.children_mut().append(&mut children);
120        r
121    }
122}
123
124macro_rules! impl_new {(
125    $(#[$attr:meta])*
126    pub struct $name:ident { $(
127        $(#[$fattr:meta])*
128        $field:ident : $typ:path
129    ),* $(,)* }
130) => (
131    $(#[$attr])*
132    #[derive(Clone, Debug, PartialEq, Serialize, JsonSchema)]
133    pub struct $name { $(
134        $(#[$fattr])* $field: $typ,
135    )* }
136    impl $name {
137        #[must_use]
138        pub fn new( $( $field: $typ, )* ) -> $name { $name { $( $field, )* } }
139    }
140)}
141
142macro_rules! impl_elem {
143    ($name:ident) => {
144        impl_new!(
145            #[derive(Default)]
146            pub struct $name {
147                #[serde(flatten)]
148                common: CommonAttributes,
149            }
150        );
151        impl_element!($name);
152    };
153    ($name:ident; +) => {
154        impl_new!(
155            #[derive(Default)]
156            pub struct $name {
157                #[serde(flatten)]
158                common: CommonAttributes,
159                #[serde(flatten)]
160                extra: extra_attributes::$name,
161            }
162        );
163        impl_element!($name);
164        impl_extra!($name, ..Default::default());
165    };
166    ($name:ident; *) => {
167        //same as above with no default
168        impl_new!(
169            pub struct $name {
170                #[serde(flatten)]
171                common: CommonAttributes,
172                #[serde(flatten)]
173                extra: extra_attributes::$name,
174            }
175        );
176        impl_element!($name);
177        impl_extra!($name);
178    };
179    ($name:ident, $childtype:ident) => {
180        impl_new!(
181            #[derive(Default)]
182            pub struct $name {
183                #[serde(flatten)]
184                common: CommonAttributes,
185                #[serde(default, skip_serializing_if = "CanBeEmpty::is_empty")]
186                children: Vec<$childtype>,
187            }
188        );
189        impl_element!($name);
190        impl_children!($name, $childtype);
191    };
192    ($name:ident, $childtype:ident; +) => {
193        impl_new!(
194            #[derive(Default)]
195            pub struct $name {
196                #[serde(flatten)]
197                common: CommonAttributes,
198                #[serde(flatten)]
199                extra: extra_attributes::$name,
200                #[serde(default, skip_serializing_if = "CanBeEmpty::is_empty")]
201                children: Vec<$childtype>,
202            }
203        );
204        impl_element!($name);
205        impl_extra!($name, ..Default::default());
206        impl_children!($name, $childtype);
207    };
208}
209
210macro_rules! impl_elems { ( $( ($($args:tt)*) )* ) => (
211    $( impl_elem!($($args)*); )*
212)}
213
214#[derive(Default, Debug, Serialize, JsonSchema)]
215pub struct Document {
216    children: Vec<StructuralSubElement>,
217}
218impl_children!(Document, StructuralSubElement);
219
220impl_elems!(
221    //structual elements
222    (Section, StructuralSubElement)
223    (Topic,   SubTopic)
224    (Sidebar, SubSidebar)
225
226    //structural subelements
227    (Title,      TextOrInlineElement)
228    (Subtitle,   TextOrInlineElement)
229    (Decoration, DecorationElement)
230    (Docinfo,    BibliographicElement)
231    (Transition)
232
233    //bibliographic elements
234    (Author,       TextOrInlineElement)
235    (Authors,      AuthorInfo)
236    (Organization, TextOrInlineElement)
237    (Address,      TextOrInlineElement; +)
238    (Contact,      TextOrInlineElement)
239    (Version,      TextOrInlineElement)
240    (Revision,     TextOrInlineElement)
241    (Status,       TextOrInlineElement)
242    (Date,         TextOrInlineElement)
243    (Copyright,    TextOrInlineElement)
244    (Field,        SubField)
245
246    //decoration elements
247    (Header, BodyElement)
248    (Footer, BodyElement)
249
250    //simple body elements
251    (Paragraph,              TextOrInlineElement)
252    (LiteralBlock,           TextOrInlineElement; +)
253    (DoctestBlock,           TextOrInlineElement; +)
254    (MathBlock,              String)
255    (Rubric,                 TextOrInlineElement)
256    (SubstitutionDefinition, TextOrInlineElement; +)
257    (Comment,                TextOrInlineElement; +)
258    (Pending)
259    (Target; +)
260    (Raw, String; +)
261    (Image; *)
262
263    //compound body elements
264    (Compound,  BodyElement)
265    (Container, BodyElement)
266
267    (BulletList,     ListItem; +)
268    (EnumeratedList, ListItem; +)
269    (DefinitionList, DefinitionListItem)
270    (FieldList,      Field)
271    (OptionList,     OptionListItem)
272
273    (LineBlock,     SubLineBlock)
274    (BlockQuote,    SubBlockQuote)
275    (Admonition,    SubTopic)
276    (Attention,     BodyElement)
277    (Hint,          BodyElement)
278    (Note,          BodyElement)
279    (Caution,       BodyElement)
280    (Danger,        BodyElement)
281    (Error,         BodyElement)
282    (Important,     BodyElement)
283    (Tip,           BodyElement)
284    (Warning,       BodyElement)
285    (Footnote,      SubFootnote; +)
286    (Citation,      SubFootnote; +)
287    (SystemMessage, BodyElement; +)
288    (Figure,        SubFigure;   +)
289    (Table,         SubTable;    +)
290
291    //table elements
292    (TableGroup, SubTableGroup; +)
293    (TableHead,  TableRow;      +)
294    (TableBody,  TableRow;      +)
295    (TableRow,   TableEntry;    +)
296    (TableEntry, BodyElement;   +)
297    (TableColspec; +)
298
299    //body sub elements
300    (ListItem, BodyElement)
301
302    (DefinitionListItem, SubDLItem)
303    (Term,               TextOrInlineElement)
304    (Classifier,         TextOrInlineElement)
305    (Definition,         BodyElement)
306
307    (FieldName, TextOrInlineElement)
308    (FieldBody, BodyElement)
309
310    (OptionListItem, SubOptionListItem)
311    (OptionGroup,    Option_)
312    (Description,    BodyElement)
313    (Option_,        SubOption)
314    (OptionString,   String)
315    (OptionArgument, String; +)
316
317    (Line,        TextOrInlineElement)
318    (Attribution, TextOrInlineElement)
319    (Label,       TextOrInlineElement)
320
321    (Caption, TextOrInlineElement)
322    (Legend,  BodyElement)
323
324    //inline elements
325    (Emphasis,              TextOrInlineElement)
326    (Literal,               String)
327    (Reference,             TextOrInlineElement; +)
328    (Strong,                TextOrInlineElement)
329    (FootnoteReference,     TextOrInlineElement; +)
330    (CitationReference,     TextOrInlineElement; +)
331    (SubstitutionReference, TextOrInlineElement; +)
332    (TitleReference,        TextOrInlineElement)
333    (Abbreviation,          TextOrInlineElement)
334    (Acronym,               TextOrInlineElement)
335    (Superscript,           TextOrInlineElement)
336    (Subscript,             TextOrInlineElement)
337    (Inline,                TextOrInlineElement)
338    (Problematic,           TextOrInlineElement; +)
339    (Generated,             TextOrInlineElement)
340    (Math,                  String)
341
342    //also have non-inline versions. Inline image is no figure child, inline target has content
343    (TargetInline, String; +)
344    (RawInline,    String; +)
345    (ImageInline; *)
346
347    //text element = String
348);
349
350impl<'a> From<&'a str> for TextOrInlineElement {
351    fn from(s: &'a str) -> Self {
352        s.to_owned().into()
353    }
354}
355
356pub trait LabelledFootnote {
357    /// Get the footnote’s/footnote reference’s label node, if available
358    ///
359    /// # Errors
360    /// Returns an error if the footnote has no label
361    fn get_label(&self) -> Result<&str, anyhow::Error>;
362}
363
364impl LabelledFootnote for Footnote {
365    fn get_label(&self) -> Result<&str, anyhow::Error> {
366        use anyhow::{Context, bail};
367
368        let SubFootnote::Label(e) = self
369            .children()
370            .first()
371            .context("Footnote has no children")?
372        else {
373            bail!("Non-auto footnote has no label");
374        };
375        match e
376            .children()
377            .first()
378            .context("Footnote label has no child")?
379        {
380            TextOrInlineElement::String(s) => Ok(s.as_ref()),
381            _ => bail!("Footnote label is not a string"),
382        }
383    }
384}
385
386impl LabelledFootnote for FootnoteReference {
387    fn get_label(&self) -> Result<&str, anyhow::Error> {
388        use anyhow::{Context, bail};
389
390        match self
391            .children()
392            .first()
393            .context("Footnote reference has no child")?
394        {
395            TextOrInlineElement::String(s) => Ok(s.as_ref()),
396            _ => bail!("Footnote reference is not a string"),
397        }
398    }
399}