typhoon_handler_macro/
lib.rs1use {
2 proc_macro::TokenStream,
3 quote::{quote, ToTokens},
4 syn::{parse::Parse, parse_macro_input, punctuated::Punctuated, Path, Token},
5};
6
7#[proc_macro]
8pub fn handlers(item: TokenStream) -> TokenStream {
9 parse_macro_input!(item as Handlers)
10 .to_token_stream()
11 .into()
12}
13
14struct Handlers {
15 instructions: Punctuated<Path, Token![,]>,
16}
17
18impl Parse for Handlers {
19 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
20 let instructions = Punctuated::<Path, Token![,]>::parse_terminated(input)?;
21
22 Ok(Handlers { instructions })
23 }
24}
25
26impl ToTokens for Handlers {
27 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
28 let instructions = self.instructions.iter().enumerate().map(|(i, val)| {
29 let i = i as u8;
30 quote! {
31 #i => handle(program_id, accounts, data, #val),
32 }
33 });
34
35 let expanded = quote! {
36 program_entrypoint!(process_instruction);
37
38 #[inline(always)]
39 pub fn process_instruction(
40 program_id: &Pubkey,
41 accounts: &[AccountInfo],
42 instruction_data: &[u8],
43 ) -> Result<(), ProgramError> {
44 let (discriminator, data) = instruction_data.split_first().ok_or(ProgramError::InvalidInstructionData)?;
45 let result = match discriminator {
46 #(#instructions)*
47 _ => Err(ProgramError::InvalidInstructionData.into()),
48 };
49
50 #[cfg(feature = "logging")]
51 result.inspect_err(log_error)?;
52
53 #[cfg(not(feature = "logging"))]
54 result?;
55
56 Ok(())
57 }
58 };
59
60 expanded.to_tokens(tokens);
61 }
62}