resource_model_macro/
lib.rs1mod 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#[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#[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}