1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};

use yarte_hir::HIR;

use crate::CodeGen;

pub struct AttrBCodeGen<T: CodeGen> {
    arg: bool,
    codegen: T,
    parent: Ident,
}

impl<T: CodeGen> AttrBCodeGen<T> {
    pub fn new(codegen: T, parent: &'static str, arg: bool) -> AttrBCodeGen<T> {
        AttrBCodeGen {
            arg,
            codegen,
            parent: format_ident!("{}", parent),
        }
    }

    fn body(&mut self, nodes: Vec<HIR>) -> TokenStream {
        self.codegen.gen(nodes)
    }
}

impl<T: CodeGen> CodeGen for AttrBCodeGen<T> {
    fn gen(&mut self, v: Vec<HIR>) -> TokenStream {
        let body = self.body(v);
        let parent = &self.parent;
        let arg = self.arg;
        if arg {
            quote! {{
                #[allow(unused_imports)]
                use #parent::*;
                macro_rules! buf_ref {
                    ($b:expr) => { &mut $b };
                }

                #body
            }}
        } else {
            quote! {
                {
                    #[allow(unused_imports)]
                    use #parent::*;
                    macro_rules! buf_ref {
                        ($b:expr) => { $b };
                    }
                    #[inline]
                    fn __yarte_context<Output: yarte::Buffer, C: FnOnce(&mut Output)>(f: C) -> Output {
                        thread_local! {
                            static SIZE: std::cell::Cell<usize> = std::cell::Cell::new(0);
                        }
                        let mut tmp = Output::with_capacity(SIZE.with(|v| v.get()));
                        f(&mut tmp);
                        SIZE.with(|v| if v.get() < tmp.len() {
                            v.set(tmp.len())
                        });
                        tmp
                    }

                    __yarte_context(|__buf| {
                        #body
                    })
                }
            }
        }
    }
}