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(accounts, data, #val),
32 }
33 });
34
35 let expanded = quote! {
36 program_entrypoint!(process_instruction);
37
38 pub fn process_instruction(
39 program_id: &Pubkey,
40 accounts: &[AccountInfo],
41 instruction_data: &[u8],
42 ) -> Result<(), ProgramError> {
43 if program_id != &crate::ID {
44 return Err(ProgramError::IncorrectProgramId);
45 }
46
47 let (discriminator, data) = instruction_data.split_first().ok_or(ProgramError::InvalidInstructionData)?;
48 let result = match discriminator {
49 #(#instructions)*
50 _ => Err(ProgramError::InvalidInstructionData.into()),
51 };
52
53 #[cfg(feature = "logging")]
54 result.inspect_err(log_error)?;
55
56 #[cfg(not(feature = "logging"))]
57 result?;
58
59 Ok(())
60 }
61 };
62
63 expanded.to_tokens(tokens);
64 }
65}