1#![cfg_attr(rustfmt, rustfmt_skip)]
3
4#[macro_export]
6macro_rules! html {
7 ($($inner:tt)*) => {{
8 let f = |__tmpl: &mut $crate::TemplateBuffer| -> () {
11 $crate::append_html!(__tmpl, html, (), $($inner)*);
12 };
13 $crate::FnRenderer::with_capacity(stringify!($($inner)*).len(), f)
15 }}
16}
17
18#[macro_export]
20macro_rules! xml {
21 ($($inner:tt)*) => {{
22 let f = |__tmpl: &mut $crate::TemplateBuffer| -> () {
23 $crate::append_html!(__tmpl, xml, (), $($inner)*);
24 };
25 $crate::FnRenderer::with_capacity(stringify!($($inner)*).len(), f)
26 }}
27}
28
29#[macro_export]
31macro_rules! owned_html {
32 ($($inner:tt)*) => {{
33 let f = move |__tmpl: &mut $crate::TemplateBuffer| -> () {
36 $crate::append_html!(__tmpl, html, (), $($inner)*);
37 };
38 $crate::FnRenderer::with_capacity(stringify!($($inner)*).len(), f)
40 }}
41}
42
43#[macro_export]
45macro_rules! owned_xml {
46 ($($inner:tt)*) => {{
47 let f = move |__tmpl: &mut $crate::TemplateBuffer| -> () {
48 $crate::append_html!(__tmpl, xml, (), $($inner)*);
49 };
50 $crate::FnRenderer::with_capacity(stringify!($($inner)*).len(), f)
51 }}
52}
53
54#[macro_export]
91macro_rules! box_html {
92 ($($inner:tt)*) => {{
93 Box::new($crate::owned_html!($($inner)*))
94 }}
95}
96
97#[macro_export]
100macro_rules! append_html {
101
102 (@close_tag html area) => {">"};
104 (@close_tag html base) => {">"};
105 (@close_tag html br) => {">"};
106 (@close_tag html col) => {">"};
107 (@close_tag html embed) => {">"};
108 (@close_tag html hr) => {">"};
109 (@close_tag html img) => {">"};
110 (@close_tag html input) => {">"};
111 (@close_tag html link) => {">"};
112 (@close_tag html meta) => {">"};
113 (@close_tag html param) => {">"};
114 (@close_tag html source) => {">"};
115 (@close_tag html track) => {">"};
116 (@close_tag html wbr) => {">"};
117 (@close_tag html $($tag:ident)-+) => {
118 concat!("></", $crate::append_html!(@stringify_compressed $($tag)-+), ">");
119 };
120 (@close_tag xml $($tag:ident)-+) => {
121 "/>"
122 };
123 (@stringify_compressed $($tok:tt)*) => {
124 concat!($(stringify!($tok)),*)
125 };
126
127 (@block_identity $b:block) => { $b };
128 (@cont $tmpl:ident, $type:ident, ($s:stmt), $($next:tt)*) => {
129 $s;
130 $crate::append_html!($tmpl, $type, (), $($next)*);
131 };
132 (@write_const $tmpl:ident, $type:ident,) => {};
133 (@write_const $tmpl:ident, $type:ident, $($p:expr),+) => {
134 $tmpl.write_raw(concat!($($p),*));
135 };
136 (@expr_and_block $tmpl:ident, $type:ident, parse_match_block, (match $($prefix:tt)*), {$($pattern:pat => {$($inner:tt)*})*} $($next:tt)*) => {
137 $crate::append_html!(@parse_match_block $tmpl, $type, (match ($($prefix)*) {$($pattern => {$($inner)*})*}), $($next)*);
138 };
139 (@expr_and_block $tmpl:ident, $type:ident, $goto:ident, ($($prefix:tt)*), {$($inner:tt)*} $($next:tt)*) => {
140 $crate::append_html!(@$goto $tmpl, $type, ($($prefix)* {$crate::append_html!($tmpl, $type, (), $($inner)*);}), $($next)*);
141 };
142 (@expr_and_block $tmpl:ident, $type:ident, $goto:ident, ($($prefix:tt)*), $first:tt $($next:tt)*) => {
143 $crate::append_html!(@expr_and_block $tmpl, $type, $goto, ($($prefix)* $first), $($next)*);
144 };
145 (@append_attrs $tmpl:ident, $type:ident, ($($p:expr),*), $($($attr:ident)-+):+ ?= $value:expr, $($rest:tt)+) => {
146 $crate::append_html!(@append_attrs $tmpl, $type, ($($p),*), $($($attr)-+):+ ?= $value);
147 $crate::append_html!(@append_attrs $tmpl, $type, (), $($rest)+);
148 };
149 (@append_attrs $tmpl:ident, $type:ident, ($($p:expr),*), $($($attr:ident)-+):+ ?= $value:expr) => {
150 match $crate::BoolOption::bool_option($value) {
151 (_, None) => {
152 $crate::append_html!(@write_const $tmpl, $type, $($p),*);
153 },
154 (true, Some(_)) => { $crate::append_html!(@append_attrs $tmpl, $type, ($($p),*), $($($attr)-+):+); }
155 (false, Some(v)) => { $crate::append_html!(@append_attrs $tmpl, $type, ($($p),*), $($($attr)-+):+ = v); }
156 };
157 };
158 (@append_attrs $tmpl:ident, $type:ident, ($($p:expr),*), $($($attr:ident)-+):+ = $value:expr, $($rest:tt)+) => {
159 $crate::append_html!(@append_attrs $tmpl, $type, ($($p),*), $($($attr)-+):+ = $value);
160 $crate::append_html!(@append_attrs $tmpl, $type, (), $($rest)+);
161 };
162 (@append_attrs $tmpl:ident, $type:ident, ($($p:expr),*), $($($attr:ident)-+):+, $($rest:tt)+) => {
163 $crate::append_html!(@append_attrs $tmpl, $type, ($($p),*), $($($attr)-+):+);
164 $crate::append_html!(@append_attrs $tmpl, $type, (), $($rest)+);
165 };
166 (@append_attrs $tmpl:ident, $type:ident, ($($p:expr),*), $($($attr:ident)-+):+ = $value:expr) => {
167 $tmpl.write_raw(concat!($($p,)* " ", $crate::append_html!(@stringify_compressed $($($attr)-+):+), "=\""));
168 $crate::RenderOnce::render_once($value, $tmpl);
169 $tmpl.write_raw("\"");
170 };
171 (@append_attrs $tmpl:ident, html, ($($p:expr),*), $($($attr:ident)-+):+) => {
172 $tmpl.write_raw(concat!($($p,)* " ", $crate::append_html!(@stringify_compressed $($($attr)-+):+)));
173 };
174 (@append_attrs $tmpl:ident, xml, ($($p:expr),*), $($($attr:ident)-+):+) => {{
175 $tmpl.write_raw(concat!($($p,)* " ",
176 $crate::append_html!(@stringify_compressed $($($attr)-+):+),
177 "=\"",
178 $crate::append_html!(@stringify_compressed $($($attr)-+):+),
179 "\""
180 ));
181 }};
182 (@parse_if $tmpl:ident, $type:ident, ($($prefix:tt)*), if let $v:pat = $e:tt $($next:tt)+) => {
185 $crate::append_html!(@expr_and_block $tmpl, $type, parse_if_block, ($($prefix)* if let $v = $e), $($next)+);
186 };
187 (@parse_if $tmpl:ident, $type:ident, ($($prefix:tt)*), if $e:tt $($next:tt)+) => {
188 $crate::append_html!(@expr_and_block $tmpl, $type, parse_if_block, ($($prefix)* if $e), $($next)+);
189 };
190 (@parse_if_block $tmpl:ident, $type:ident, ($($prefix:tt)*), else if $($next:tt)*) => {
193 $crate::append_html!(@parse_if $tmpl, $type, ($($prefix)* else), if $($next)*);
194 };
195 (@parse_if_block $tmpl:ident, $type:ident, ($($prefix:tt)*), else {$($inner:tt)*} $($next:tt)*) => {
197 $crate::append_html!(@cont $tmpl, $type, ($($prefix)* else {$crate::append_html!($tmpl, $type, (), $($inner)*);}), $($next)*);
198 };
199 (@parse_if_block $tmpl:ident, $type:ident, ($($prefix:tt)*), $($next:tt)*) => {
201 $crate::append_html!(@cont $tmpl, $type, ($($prefix)*), $($next)*);
202 };
203 (@parse_match_block $tmpl:ident, $type:ident, (match ($($prefix:tt)*) {$($pattern:pat => {$($inner:tt)*})*}), $($next:tt)*) => {
205 $crate::append_html!(@cont $tmpl, $type, (match ($($prefix)*) {$(
206 $pattern => { $crate::append_html!($tmpl, $type, (), $($inner)*); }
207 )*}), $($next)*);
208 };
209 ($tmpl:ident, $type:ident, ($($p:expr),*), @ if $($next:tt)+) => {
211 $crate::append_html!(@write_const $tmpl, $type, $($p),*);
212 $crate::append_html!(@parse_if $tmpl, $type, (), if $($next)*);
213 };
214 ($tmpl:ident, $type:ident, ($($p:expr),*), @ for $v:pat in $e:tt $($next:tt)*) => {
215 $crate::append_html!(@write_const $tmpl, $type, $($p),*);
216 $crate::append_html!(@expr_and_block $tmpl, $type, cont, (for $v in $e), $($next)*);
217 };
218 ($tmpl:ident, $type:ident, ($($p:expr),*), @ while let $v:pat = $e:tt $($next:tt)*) => {
219 $crate::append_html!(@write_const $tmpl, $type, $($p),*);
220 $crate::append_html!(@expr_and_block $tmpl, $type, cont, (while let $v = $e), $($next)*);
221 };
222 ($tmpl:ident, $type:ident, ($($p:expr),*), @ while $e:tt $($next:tt)*) => {
223 $crate::append_html!(@write_const $tmpl, $type, $($p),*);
224 $crate::append_html!(@expr_and_block $tmpl, $type, cont, (while $e), $($next)*);
225 };
226 ($tmpl:ident, $type:ident, ($($p:expr),*), @ match $e:tt $($next:tt)+) => {
227 $crate::append_html!(@write_const $tmpl, $type, $($p),*);
228 $crate::append_html!(@expr_and_block $tmpl, $type, parse_match_block, (match $e), $($next)*);
229 };
230 ($tmpl:ident, $type:ident, ($($p:expr),*), : {$($code:tt)*} $($next:tt)*) => {
231 $crate::append_html!(@write_const, $tmpl, $type, $($p),*);
232 $crate::RenderOnce::render_once({$($code)*}, $tmpl);
233 $crate::append_html!($tmpl, $type, (), $($next)*);
234 };
235 ($tmpl:ident, $type:ident, ($($p:expr),*), : $code:expr; $($next:tt)* ) => {
236 $crate::append_html!(@write_const $tmpl, $type, $($p),*);
237 $crate::RenderOnce::render_once($code, $tmpl);
238 $crate::append_html!($tmpl, $type, (), $($next)*);
239 };
240 ($tmpl:ident, $type:ident, ($($p:expr),*), : $code:expr ) => {
241 $crate::append_html!(@write_const $tmpl, $type, $($p),*);
242 $crate::RenderOnce::render_once($code, $tmpl);
243 };
244 ($tmpl:ident, $type:ident, ($($p:expr),*), |$var:ident| {$($code:tt)*} $($next:tt)*) => {
245 $crate::append_html!(@write_const $tmpl, $type, $($p),*);
246 {
247 let $var: &mut $crate::TemplateBuffer = &mut *$tmpl;
248 $crate::append_html!(@block_identity {$($code)*})
249 }
250 $crate::append_html!($tmpl, $type, (), $($next)*);
251 };
252 ($tmpl:ident, $type:ident, ($($p:expr),*), |mut $var:ident| {$($code:tt)*} $($next:tt)*) => {
253 $crate::append_html!(@write_const $tmpl, $type, $($p),*);
254 {
255 let mut $var: &mut $crate::TemplateBuffer = &mut *$tmpl;
256 $crate::append_html!(@block_identity {$($code)*})
257 }
258 $crate::append_html!($tmpl, $type, (), $($next)*);
259 };
260 ($tmpl:ident, $type:ident, ($($p:expr),*), |$var:ident| $code:stmt; $($next:tt)* ) => {
261 $crate::append_html!(@write_const $tmpl, $type, $($p),*);
262 {
263 let $var: &mut $crate::TemplateBuffer = &mut *$tmpl;
264 $code;
265 }
266 $crate::append_html!($tmpl, $type, (), $($next)*);
267 };
268 ($tmpl:ident, $type:ident, ($($p:expr),*), |mut $var:ident| $code:stmt; $($next:tt)* ) => {
269 $crate::append_html!(@write_const $tmpl, $type, $($p),*);
270 {
271 let mut $var: &mut $crate::TemplateBuffer = &mut *$tmpl;
272 $code;
273 }
274 $crate::append_html!($tmpl, $type, (), $($next)*);
275 };
276 ($tmpl:ident, $type:ident, ($($p:expr),*), |$var:ident| $code:stmt ) => {{
277 $crate::append_html!(@write_const $tmpl, $type, $($p),*);
278 let $var: &mut $crate::TemplateBuffer = &mut *$tmpl;
279 $code;
280 }};
281 ($tmpl:ident, $type:ident, ($($p:expr),*), |mut $var:ident| $code:stmt ) => {{
282 $crate::append_html!(@write_const $tmpl, $type, $($p),*);
283 let mut $var: &mut $crate::TemplateBuffer = &mut *$tmpl;
284 $code;
285 }};
286 ($tmpl:ident, $type:ident, ($($p:expr),*), $($tag:ident)-+($($attrs:tt)+) { $($children:tt)* } $($next:tt)* ) => {
287 $crate::append_html!(@append_attrs $tmpl, $type, ($($p,)* "<", $crate::append_html!(@stringify_compressed $($tag)-+)), $($attrs)+);
288 $crate::append_html!($tmpl, $type, (">"), $($children)*);
289 $crate::append_html!($tmpl, $type, ("</", $crate::append_html!(@stringify_compressed $($tag)-+), ">"), $($next)*);
290 };
291 ($tmpl:ident, $type:ident, ($($p:expr),*), $($tag:ident)-+($($attr:tt)+) : $e:expr; $($next:tt)* ) => {
292 $crate::append_html!($tmpl, $type, ($($p),*), $($tag)-+($($attr)+) { : $e; } $($next)* );
293 };
294 ($tmpl:ident, $type:ident, ($($p:expr),*), $($tag:ident)-+($($attr:tt)+) : $e:expr) => {
295 $crate::append_html!($tmpl, $type, ($($p),*), $($tag)-+($($attr)+) { : $e });
296 };
297 ($tmpl:ident, $type:ident, ($($p:expr),*), $($tag:ident)-+($($attr:tt)+) : {$($code:tt)*} $($next:tt)* ) => {
298 $crate::append_html!($tmpl, $type, ($($p),*), $($tag)-+($($attr)+) { : {$($code)*} } $($next)* );
299 };
300 ($tmpl:ident, $type:ident, ($($p:expr),*), $($tag:ident)-+($($attrs:tt)+); $($next:tt)*) => {
301 $crate::append_html!(@append_attrs $tmpl, $type, ($($p,)* "<", $crate::append_html!(@stringify_compressed $($tag)-+)), $($attrs)+);
302 $crate::append_html!($tmpl, $type, ($crate::append_html!(@close_tag $type $($tag)-+)), $($next)*);
303 };
304 ($tmpl:ident, $type:ident, ($($p:expr),*), $($tag:ident)-+($($attrs:tt)+)) => {
305 $crate::append_html!(@append_attrs $tmpl, $type, ($($p,)* "<", $crate::append_html!(@stringify_compressed $($tag)-+)), $($attrs)+);
306 $tmpl.write_raw($crate::append_html!(@close_tag $type $($tag)-+));
307 };
308 ($tmpl:ident, $type:ident, ($($p:expr),*), $($tag:ident)-+ { $($children:tt)* } $($next:tt)* ) => {
309 $crate::append_html!($tmpl, $type, ($($p,)* "<", $crate::append_html!(@stringify_compressed $($tag)-+), ">"), $($children)*);
310 $crate::append_html!($tmpl, $type, ("</", $crate::append_html!(@stringify_compressed $($tag)-+), ">"), $($next)*);
311 };
312 ($tmpl:ident, $type:ident, ($($p:expr),*), $($tag:ident)-+ : $e:expr; $($next:tt)* ) => {
313 $crate::append_html!($tmpl, $type, ($($p),*), $($tag)-+ { : $e; } $($next)* );
314 };
315 ($tmpl:ident, $type:ident, ($($p:expr),*), $($tag:ident)-+ : {$($code:tt)*} $($next:tt)* ) => {
316 $crate::append_html!($tmpl, $type, ($($p),*), $($tag)-+ { : {$($code)*} } $($next)* );
317 };
318 ($tmpl:ident, $type:ident, ($($p:expr),*), $($tag:ident)-+; $($next:tt)*) => {
319 $crate::append_html!($tmpl, $type, ($($p,)* "<", $crate::append_html!(@stringify_compressed $($tag)-+), $crate::append_html!(@close_tag $type $($tag)-+)), $($next)*);
320 };
321 ($tmpl:ident, $type:ident, ($($p:expr),*), $($tag:ident)-+ : $e:expr) => {
322 $crate::append_html!($tmpl, $type, ($($p),*), $($tag)-+ { : $e; });
323 };
324 ($tmpl:ident, $type:ident, ($($p:expr),*), $($tag:ident)-+) => {
325 $crate::append_html!(@write_const $tmpl, $type, $($p,)* "<", $crate::append_html!(@stringify_compressed $($tag)-+), $crate::append_html!(@close_tag $type $($tag)-+));
326 };
327 ($tmpl:ident, $type:ident, ($($p:expr),*),) => {
328 $crate::append_html!(@write_const $tmpl, $type, $($p),*);
329 };
330 ($tmpl:ident, $type:ident, ($($p:expr),*), $t:tt $($tr:tt)*) => {
331 compile_error!(concat!("unexpected token tree: ", stringify!($t), "\n\nYou're probably missing a semicolon somewhere."));
332 }
333}
334
335#[macro_export]
382macro_rules! template {
383 ($name:ident ($($field:ident : &$typ:ty),*) { $($tmpl:tt)* } $($rest:tt)*) => {
384 struct $name<'a> { $( $field: &'a $typ),* }
385 impl<'a> $name<'a> {
386 pub fn new($($field: &'a $typ),*) -> Self {
387 $name { $( $field: $field),* }
388 }
389 }
390 impl<'a> $crate::RenderOnce for $name<'a> {
391 fn render_once(self, tmpl: &mut $crate::TemplateBuffer) {
392 $crate::Render::render(&self, tmpl);
393 }
394 }
395 impl<'a> $crate::RenderMut for $name<'a> {
396 fn render_mut(&mut self, tmpl: &mut $crate::TemplateBuffer) {
397 $crate::Render::render(self, tmpl);
398 }
399 }
400 impl<'a> $crate::Render for $name<'a> {
401 fn render(&self, tmpl: &mut $crate::TemplateBuffer) {
402 let &$name { $($field),* } = self;
403 tmpl << $crate::html! { $($tmpl)* };
404 }
405 }
406 $crate::template!($($rest)*);
407 };
408 (pub $name:ident ($($field:ident : &$typ:ty),*) { $($tmpl:tt)* } $($rest:tt)*) => {
409 pub struct $name<'a> { $( $field: &'a $typ),* }
410 impl<'a> $name<'a> {
411 pub fn new($($field: &'a $typ),*) -> Self {
412 $name { $( $field: $field),* }
413 }
414 }
415 impl<'a> $crate::RenderOnce for $name<'a> {
416 fn render_once(self, tmpl: &mut $crate::TemplateBuffer) {
417 $crate::Render::render(&self, tmpl);
418 }
419 }
420 impl<'a> $crate::RenderMut for $name<'a> {
421 fn render_mut(&mut self, tmpl: &mut $crate::TemplateBuffer) {
422 $crate::Render::render(self, tmpl);
423 }
424 }
425 impl<'a> $crate::Render for $name<'a> {
426 fn render(&self, tmpl: &mut $crate::TemplateBuffer) {
427 let &$name { $($field),* } = self;
428 tmpl << $crate::html! { $($tmpl)* };
429 }
430 }
431 $crate::template!($($rest)*);
432 };
433 () => {}
434}
435
436#[macro_export]
468macro_rules! labels {
469
470 ($($tail:tt)+) => (
471 $crate::labels_sep_by!(" "; $($tail)*)
472 );
473
474}
475
476#[macro_export]
510macro_rules! labels_sep_by {
511
512 (@inner_expand $has_before:expr; $sep:expr; $tmpl:ident $item:expr) => {
513 if $has_before {
514 $crate::RenderOnce::render_once($sep, $tmpl);
515 }
516 $crate::RenderOnce::render_once($item, $tmpl);
517 };
518
519 (@inner_expand $has_before:expr; $sep:expr; $tmpl:ident $item:expr => $should_include:expr) => {
520 if $should_include {
521 if $has_before {
522 $crate::RenderOnce::render_once($sep, $tmpl);
523 }
524 $crate::RenderOnce::render_once($item, $tmpl);
525 }
526 };
527
528 (@inner_expand $has_before:expr; $sep:expr; $tmpl:ident $item:expr, $($tail:tt)+) => {
529 if $has_before {
530 $crate::RenderOnce::render_once($sep, $tmpl);
531 }
532 $crate::RenderOnce::render_once($item, $tmpl);
533 $crate::labels_sep_by!(@inner_expand true; $sep; $tmpl $($tail)*);
534 };
535
536 (@inner_expand $has_before:expr; $sep:expr; $tmpl:ident $item:expr => $should_include:expr, $($tail:tt)+) => {
537 if $should_include {
538 if $has_before {
539 $crate::RenderOnce::render_once($sep, $tmpl);
540 }
541 $crate::RenderOnce::render_once($item, $tmpl);
542 }
543 $crate::labels_sep_by!(@inner_expand $has_before || $should_include; $sep; $tmpl $($tail)*);
544 };
545
546 ($sep:expr; $item:expr) => {
549
550 $crate::FnRenderer::new(|tmpl| {
551 $crate::RenderOnce::render_once($item, tmpl);
552 })
553
554 };
555
556 ($sep:expr; $item:expr => $should_include:expr) => {
557
558 $crate::FnRenderer::new(|tmpl| {
559 if $should_include {
560 $crate::RenderOnce::render_once($item, tmpl);
561 }
562 })
563
564 };
565
566 ($sep:expr; $item:expr, $($tail:tt)+) => {
567
568 $crate::FnRenderer::new(|tmpl| {
569 $crate::RenderOnce::render_once($item, tmpl);
570 $crate::labels_sep_by!(@inner_expand true; $sep; tmpl $($tail)*);
571 })
572
573 };
574
575 ($sep:expr; $item:expr => $should_include:expr, $($tail:tt)+) => {
576
577 $crate::FnRenderer::new(|tmpl| {
578 if $should_include {
579 $crate::RenderOnce::render_once($item, tmpl);
580 }
581 $crate::labels_sep_by!(@inner_expand $should_include; $sep; tmpl $($tail)*);
582 })
583
584 };
585
586}