bolt_helpers_system_template/
lib.rs1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use quote::quote;
5use syn::parse::{Parse, ParseStream, Result};
6use syn::{parse_macro_input, Ident, LitInt, Token};
7
8#[proc_macro_attribute]
10pub fn system_template(attr: TokenStream, item: TokenStream) -> TokenStream {
11 let attr_p = parse_macro_input!(attr as SystemTemplateInput);
12
13 let max_components = attr_p.max_components;
14
15 let mut input: syn::ItemMod = syn::parse(item).expect("Failed to parse input module");
17
18 let funcs = (2..=max_components).map(|i| {
20 let func_name = syn::Ident::new(&format!("execute_{}", i), proc_macro2::Span::call_site());
21 let data_struct = syn::Ident::new(&format!("SetData{}", i), proc_macro2::Span::call_site());
22 let return_values = vec![quote!(Vec::<u8>::new()); i];
23 let return_types = vec![quote!(Vec<u8>); i];
24 quote! {
25 pub fn #func_name(_ctx: Context<#data_struct>, _args: Vec<u8>) -> Result<(#(#return_types),*)> {
26 Ok((#(#return_values),*))
27 }
28 }
29 });
30
31 if let Some((brace, mut content)) = input.content.take() {
33 for func in funcs {
34 let parsed_func: syn::Item =
35 syn::parse2(func).expect("Failed to parse generated function");
36 content.push(parsed_func);
37 }
38
39 input.content = Some((brace, content));
40 }
41
42 let data_def = (2..=max_components).map(|i| {
43 let data_struct = syn::Ident::new(&format!("SetData{}", i), proc_macro2::Span::call_site());
44 let fields = (1..=i).map(|n| {
45 let field_name =
46 syn::Ident::new(&format!("component{}", n), proc_macro2::Span::call_site());
47 quote! {
48 #[account()]
49 pub #field_name: UncheckedAccount<'info>,
51 }
52 });
53 let struct_def = quote! {
54 #[derive(Accounts)]
55 pub struct #data_struct<'info> {
56 #(#fields)*
57 #[account()]
58 pub authority: Signer<'info>,
59 }
60 };
61 quote! {
62 #struct_def
63 }
64 });
65
66 let output = quote! {
68 #input
69 #(#data_def)*
70 };
71 output.into()
72}
73
74struct SystemTemplateInput {
76 max_components: usize,
77}
78
79impl Parse for SystemTemplateInput {
81 fn parse(input: ParseStream) -> Result<Self> {
82 let _ = input.parse::<Ident>()?; let _ = input.parse::<Token![=]>()?; let max_components: LitInt = input.parse()?; let max_value = max_components.base10_parse()?;
86 Ok(SystemTemplateInput {
87 max_components: max_value,
88 })
89 }
90}