continuation_router_syn/
lib.rs

1#![allow(clippy::needless_return)]
2use proc_macro::TokenStream;
3use quote::quote;
4use syn::{parse_macro_input, AttributeArgs, DeriveInput, Ident, Meta, NestedMeta};
5
6#[proc_macro_attribute]
7pub fn router_action(args: TokenStream, input: TokenStream) -> TokenStream {
8    let args = parse_macro_input!(args as AttributeArgs);
9    let mut ast = parse_macro_input!(input as DeriveInput);
10    match &mut ast.data {
11        syn::Data::Struct(ref mut _struct_data) => {
12            // let accounts_name = &Ident::new(format!("{}Accounts", name).as_str(), name.span());
13            let name = &ast.ident;
14            let action_name = &Ident::new(format!("{}", name).as_str(), name.span());
15
16            let process_impl = match &*args {
17                [NestedMeta::Meta(Meta::Path(path))]
18                    if path
19                        .clone()
20                        .segments
21                        .into_iter()
22                        .any(|s| s.ident == "pass_through") =>
23                {
24                    quote! {
25                        impl<'info> crate::processor::ActionInputOutput<'info> for ActionContext<'_, '_, '_, 'info, #action_name<'info>> {
26                            fn input_account(&self) -> &Account<'info, TokenAccount> {
27                                &self.action.input
28                            }
29
30                            fn output_account(&self) -> &Account<'info, TokenAccount> {
31                                &self.action.output
32                            }
33                        }
34
35                        impl<'info> crate::processor::Processor<'info> for ActionContext<'_, '_, '_, 'info, #action_name<'info>> {
36                            fn process_unchecked(
37                                &self,
38                                amount_in: u64,
39                                minimum_amount_out: u64
40                            ) -> Result<()> {
41                                crate::router_action_processor::process_action(
42                                    CpiContext::new(
43                                        self.swap_program.clone(),
44                                        self.remaining_accounts.to_vec()
45                                    ),
46                                    Self::TYPE.into(),
47                                    amount_in,
48                                    minimum_amount_out,
49                                )
50                            }
51                        }
52                    }
53                }
54                _ => quote! {
55                    impl<'info> crate::processor::ActionInputOutput<'info> for ActionContext<'_, '_, '_, 'info, #action_name<'info>> {
56                        fn input_account(&self) -> &Account<'info, TokenAccount> {
57                            self.action.input_account()
58                        }
59                        fn output_account(&self) -> &Account<'info, TokenAccount> {
60                            self.action.output_account()
61                        }
62                    }
63
64                    impl<'info> crate::processor::Processor<'info> for ActionContext<'_, '_, '_, 'info, #action_name<'info>> {
65                        fn process_unchecked(
66                            &self,
67                            amount_in: u64,
68                            minimum_amount_out: u64
69                        ) -> Result<()> {
70                            ProcessAction::process(self, amount_in, minimum_amount_out)
71                        }
72                    }
73                },
74            };
75
76            ast.ident = action_name.clone();
77
78            return quote! {
79                // cannot use this because anchor IDL can't see this
80                // #[derive(Accounts)]
81                #ast
82
83                // cannot use this because anchor IDL can't see this
84                // #[derive(Accounts)]
85                // pub struct #accounts_name<'info> {
86                //     pub continuation: ContinuationContext<'info>,
87                //     pub action: #action_name<'info>,
88                // }
89
90                #process_impl
91
92                impl<'info> crate::Action for ActionContext<'_, '_, '_, '_, #action_name<'info>> {
93                    const TYPE: crate::ActionType = crate::ActionType::#action_name;
94                }
95            }
96            .into();
97        }
98        _ => panic!("`add_field` has to be used with structs "),
99    }
100}