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
110impl_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);