Skip to main content

resource_model_macro/
lib.rs

1mod codegen;
2mod spec;
3mod validate;
4
5use proc_macro::TokenStream;
6use syn::{parse_macro_input, LitStr};
7
8fn process_yaml(yaml_str: &str) -> TokenStream {
9    let spec: spec::Spec = match serde_yaml::from_str(yaml_str) {
10        Ok(s) => s,
11        Err(e) => {
12            let msg = format!("resource_model!: failed to parse YAML: {e}");
13            return quote::quote! { compile_error!(#msg); }.into();
14        }
15    };
16
17    let errors = validate::validate(&spec);
18    if !errors.is_empty() {
19        let msgs: Vec<proc_macro2::TokenStream> = errors
20            .iter()
21            .map(|e| {
22                let msg = format!("resource_model!: {e}");
23                quote::quote! { compile_error!(#msg); }
24            })
25            .collect();
26        return quote::quote! { #(#msgs)* }.into();
27    }
28
29    codegen::generate(&spec).into()
30}
31
32/// Accepts an inline YAML string literal.
33#[proc_macro]
34pub fn resource_model(input: TokenStream) -> TokenStream {
35    let lit = parse_macro_input!(input as LitStr);
36    process_yaml(&lit.value())
37}
38
39/// Accepts a file path (relative to the crate root) and reads the YAML at compile time.
40#[proc_macro]
41pub fn resource_model_file(input: TokenStream) -> TokenStream {
42    let lit = parse_macro_input!(input as LitStr);
43    let rel_path = lit.value();
44
45    let manifest_dir = match std::env::var("CARGO_MANIFEST_DIR") {
46        Ok(d) => d,
47        Err(_) => {
48            return quote::quote! {
49                compile_error!("resource_model_file!: CARGO_MANIFEST_DIR not set");
50            }
51            .into();
52        }
53    };
54
55    let full_path = std::path::Path::new(&manifest_dir).join(&rel_path);
56    let yaml_str = match std::fs::read_to_string(&full_path) {
57        Ok(s) => s,
58        Err(e) => {
59            let msg = format!(
60                "resource_model_file!: cannot read '{}': {e}",
61                full_path.display()
62            );
63            return quote::quote! { compile_error!(#msg); }.into();
64        }
65    };
66
67    process_yaml(&yaml_str)
68}