ai_json_template_derive/
lib.rs1#[macro_use] mod imports; use imports::*;
3
4xp!{gather_doc_comments}
5xp!{comma_separated_expression}
6xp!{classify_field_type}
7
8#[proc_macro_derive(AiJsonTemplate)]
9pub fn derive_ai_json_template(input: TokenStream) -> TokenStream {
10 trace!("Entering derive_ai_json_template macro.");
11
12 let ast = parse_macro_input!(input as DeriveInput);
13 let struct_ident = &ast.ident;
14 let struct_span = ast.span();
15 let struct_name_str = struct_ident.to_string();
16 trace!("Processing struct: {}", struct_name_str);
17
18 let struct_docs_vec = gather_doc_comments(&ast.attrs);
20 let struct_docs_str = struct_docs_vec.join("\n");
21 trace!("Gathered struct doc comments = {:?}", struct_docs_vec);
22
23 let fields = match &ast.data {
24 Data::Struct(DataStruct { fields: Fields::Named(named), .. }) => {
25 trace!("Struct has named fields.");
26 &named.named
27 },
28 _ => {
29 let err = syn::Error::new(
30 struct_span,
31 "AiJsonTemplate derive only supports a named struct."
32 );
33 return err.to_compile_error().into();
34 }
35 };
36
37 let mut field_inits = Vec::new();
38 for field in fields {
39 let field_ident = match &field.ident {
40 Some(id) => id,
41 None => {
42 let err = syn::Error::new(
43 field.span(),
44 "Unnamed fields are not supported by AiJsonTemplate."
45 );
46 return err.to_compile_error().into();
47 }
48 };
49 let field_name_str = field_ident.to_string();
50 trace!("Analyzing field: {}", field_name_str);
51
52 let field_docs = gather_doc_comments(&field.attrs).join("\n");
54 trace!("Field docs => {:?}", field_docs);
55
56 let ty = &field.ty;
57 let type_q = quote!(#ty).to_string();
58 trace!("Field type => {}", type_q);
59
60 if let Some(expr) = classify_field_type(ty, &field_docs) {
61 field_inits.push(quote! {
62 map.insert(#field_name_str.to_string(), #expr);
63 });
64 } else {
65 let err_msg = format!("Unsupported field type for AiJsonTemplate: {}", type_q);
66 trace!("ERROR: {}", err_msg);
67 let err = syn::Error::new(ty.span(), err_msg);
68 return err.to_compile_error().into();
69 }
70 }
71
72 let expanded = quote! {
73 impl AiJsonTemplate for #struct_ident {
74 fn to_template() -> serde_json::Value {
75 tracing::trace!("AiJsonTemplate::to_template for struct {}", #struct_name_str);
76
77 let mut root = serde_json::Map::new();
78 root.insert("struct_docs".to_string(), serde_json::Value::String(#struct_docs_str.to_string()));
79 root.insert("struct_name".to_string(), serde_json::Value::String(#struct_name_str.to_string()));
80
81 let mut map = serde_json::Map::new();
82 #(#field_inits)*
83
84 root.insert("fields".to_string(), serde_json::Value::Object(map));
85 serde_json::Value::Object(root)
86 }
87 }
88 };
89
90 trace!("Exiting derive_ai_json_template macro for {}", struct_name_str);
91 expanded.into()
92}