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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
extern crate proc_macro;
use proc_macro::TokenStream;
use std::str::FromStr;
use syn::export::ToTokens;
use syn::{parse_macro_input, Fields, ItemStruct};

#[proc_macro_attribute]
pub fn template(metadata: TokenStream, input: TokenStream) -> TokenStream {
    let template_exp = metadata.to_string();
    let original_struct = input.to_string();
    let input = parse_macro_input!(input as ItemStruct);
    let struct_name = input.ident.to_string();
    let mut fields: Vec<(String, String)> = vec![];
    if let Fields::Named(n) = input.fields {
        fields = n
            .named
            .iter()
            .map(|x| {
                (
                    x.ident.as_ref().unwrap().to_string(),
                    x.ty.clone().into_token_stream().to_string(),
                )
            })
            .collect();
    }

    let mut args: Vec<String> = vec![];
    let mut extractor_exprs: Vec<String> = vec![];
    let mut execute_exprs: Vec<String> = vec![];
    let mut c = 0;
    for (field_name, field_type) in fields.iter() {
        if field_type == "String" {
            extractor_exprs.push(
                [
                    "const ",
                    field_name,
                    " = this.readUtf8FromMemory(a",
                    &c.to_string(),
                    ",a",
                    &(c + 1).to_string(),
                    ");",
                ]
                .join(""),
            );
            execute_exprs.push(
                [
                    "let a",
                    &c.to_string(),
                    " = self.",
                    field_name,
                    ".as_ptr() as u32;\nlet a",
                    &(c + 1).to_string(),
                    " = self.",
                    field_name,
                    ".len() as u32;",
                ]
                .join(""),
            );
            args.push(["a", &c.to_string()].join(""));
            c += 1;
            args.push(["a", &c.to_string()].join(""));
            c += 1;
        } else {
            panic!("unsupported type");
        }
    }
    let args = args.join(",");
    let extractor_exprs = extractor_exprs.join("\n");
    let execute_exprs = execute_exprs.join("\n");

    TokenStream::from_str(&format!(r#"
    {}
    
    struct {}Builder {{
        fn_builder: lit_html::js::JSFunction,
    }}
    
    impl Default for {}Builder {{
        fn default() -> Self {{
            let mut fn_text = &["function builder(","{}","){{\n","{}","const result = window.LitHtml.html`",{},"`;\nreturn this.storeObject(result);\n}}"].join("");
            {}Builder {{
                fn_builder: lit_html::js::register_function(&fn_text),
            }}
        }}
    }}
    
    impl lit_html::Template for {} {{
        fn execute(&self) -> f64 {{
            let builder = globals::get::<{}Builder>();
            {}
            builder.fn_builder.invoke_{}({})
        }}
    }}
    "#,original_struct,struct_name,struct_name,args,extractor_exprs,template_exp,struct_name,struct_name,struct_name,execute_exprs,c,args)).unwrap()
}