rst_renderer/html/
multi.rs

1use std::{borrow::Borrow, io::Write};
2
3use anyhow::Error;
4
5use super::{HTMLRender, HTMLRenderer};
6
7use document_tree::{element_categories as c, elements as e};
8
9macro_rules! impl_html_render_multi {
10    (
11        $type1:path $( [$($post1:tt)+] )?,
12        $( $type:path $( [$($post:tt)+] )? ),+
13    ) => {
14        impl_html_render_multi!($type1 $([$($post1)+])?);
15        $( impl_html_render_multi!($type $([$($post)+])?); )+
16    };
17    ( $type:path ) => {
18        impl_html_render_multi!($type[""]);
19    };
20    ( $type:path [ $post:expr ] ) => {
21        impl HTMLRender for [&$type] {
22            fn render_html<W: Write>(&self, renderer: &mut HTMLRenderer<W>) -> Result<(), Error> {
23                write_optional_newlines::<$type, _, _>(renderer, self, $post)
24            }
25        }
26        impl HTMLRender for [$type] {
27            fn render_html<W: Write>(&self, renderer: &mut HTMLRenderer<W>) -> Result<(), Error> {
28                write_optional_newlines::<$type, _, _>(renderer, self, $post)
29            }
30        }
31    };
32}
33
34fn write_optional_newlines<R, E, W>(
35    renderer: &mut HTMLRenderer<W>,
36    elems: &[E],
37    post: &str,
38) -> Result<(), Error>
39where
40    R: HTMLRender,
41    E: Borrow<R>,
42    W: Write,
43{
44    let many = elems.len() > 1;
45    if many {
46        write!(renderer.stream, "{post}")?;
47    }
48    for c in elems {
49        c.borrow().render_html(renderer)?;
50        if many {
51            write!(renderer.stream, "{post}")?;
52        }
53    }
54    Ok(())
55}
56
57macro_rules! impl_html_render_multi_body {
58    ( $type1:path, $( $type:path ),+ ) => {
59        impl_html_render_multi_body!($type1);
60        $( impl_html_render_multi_body!($type); )+
61    };
62    ( $type:path ) => {
63        impl HTMLRender for [$type] {
64            fn render_html<W>(&self, renderer: &mut HTMLRenderer<W>) -> Result<(), Error>
65            where
66                W: Write,
67            {
68                let many = self.len() > 1;
69                if many {
70                    writeln!(renderer.stream)?;
71                }
72                let mut footnotes: Vec<&e::Footnote> = vec![];
73                for c in self {
74                    if let Ok(&c::BodyElement::Footnote(ref f)) = c.try_into() {
75                        footnotes.push(f.as_ref());
76                        continue;
77                    }
78                    write_footnotes(renderer, &footnotes)?;
79                    c.render_html(renderer)?;
80                    if many {
81                        writeln!(renderer.stream)?;
82                    }
83                }
84                write_footnotes(renderer, &footnotes)?;
85                Ok(())
86            }
87        }
88    };
89}
90
91fn write_footnotes<W>(
92    renderer: &mut HTMLRenderer<W>,
93    footnotes: &[&e::Footnote],
94) -> Result<(), Error>
95where
96    W: Write,
97{
98    if footnotes.is_empty() {
99        return Ok(());
100    }
101    writeln!(renderer.stream, "<ol>")?;
102    for f in footnotes {
103        f.render_html(renderer)?;
104        writeln!(renderer.stream)?;
105    }
106    writeln!(renderer.stream, "</ol>")?;
107    Ok(())
108}
109
110// Impl
111
112impl_html_render_multi!(
113    c::TextOrInlineElement,
114    c::SubSidebar,
115    c::SubLineBlock,
116    c::SubBlockQuote,
117    c::SubTopic,
118    c::SubFigure,
119    e::ListItem["\n"],
120    e::DefinitionListItem,
121    e::Field,
122    e::OptionListItem,
123    e::Footnote["\n"],
124    String
125);
126
127impl_html_render_multi_body!(c::StructuralSubElement, c::SubStructure, c::BodyElement);