crown_derive/
lib.rs

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}