1mod marshal;
2
3use minijinja::{context, Environment};
4use proc_macro::{Span, TokenStream};
5use quote::quote;
6use std::fs;
7use syn::{parse_macro_input, LitStr};
8
9#[proc_macro_derive(Marshal, attributes(marshal))]
10pub fn marshal(input: TokenStream) -> TokenStream {
11 marshal::marshal(input)
12}
13
14#[proc_macro]
15pub fn jinja(input: TokenStream) -> TokenStream {
16 let tmpl = parse_macro_input!(input as LitStr);
17
18 let rendered = match render(&tmpl.value()) {
19 Ok(result) => result,
20 Err(err) => {
21 return syn::Error::new(
22 Span::call_site().into(),
23 format!("Jinja rendering error: {}", err),
24 )
25 .to_compile_error()
26 .into();
27 }
28 };
29
30 let expr = LitStr::new(&rendered, Span::call_site().into());
31 quote! { #expr }.into()
32}
33
34#[proc_macro]
35pub fn jinja_file(input: TokenStream) -> TokenStream {
36 let path = parse_macro_input!(input as LitStr).value();
37
38 let content = match fs::read_to_string(&path) {
39 Ok(content) => content,
40 Err(err) => {
41 return syn::Error::new(
42 Span::call_site().into(),
43 format!("Failed to read file '{}': {}", path, err),
44 )
45 .to_compile_error()
46 .into();
47 }
48 };
49
50 let content = LitStr::new(&content, Span::call_site().into());
51 jinja(
52 quote! {
53 #content
54 }
55 .into(),
56 )
57}
58
59fn render(template: &str) -> Result<String, Box<dyn std::error::Error>> {
60 let env = Environment::new();
61 let tmpl = env.template_from_str(template)?;
62
63 Ok(tmpl.render(context! {})?)
64}