1#![no_std]
2
3use {bytemuck::NoUninit, paste::paste};
4
5mod args;
6mod remaining_accounts;
7
8pub use args::*;
9use {
10 pinocchio::{account_info::AccountInfo, cpi::set_return_data, pubkey::Pubkey},
11 typhoon_errors::Error,
12};
13
14pub trait HandlerContext<'a>: Sized {
15 fn from_entrypoint(
16 program_id: &Pubkey,
17 accounts: &mut &'a [AccountInfo],
18 instruction_data: &mut &'a [u8],
19 ) -> Result<Self, Error>;
20}
21
22pub trait Handler<'a, T> {
23 type Output: NoUninit;
24
25 fn call(
26 self,
27 program_id: &Pubkey,
28 accounts: &mut &'a [AccountInfo],
29 instruction_data: &mut &'a [u8],
30 ) -> Result<Self::Output, Error>;
31}
32
33impl<'a, F, O> Handler<'a, ()> for F
34where
35 F: FnOnce() -> Result<O, Error>,
36 O: NoUninit,
37{
38 type Output = O;
39
40 fn call(
41 self,
42 _program_id: &Pubkey,
43 _accounts: &mut &'a [AccountInfo],
44 _instruction_data: &mut &'a [u8],
45 ) -> Result<Self::Output, Error> {
46 (self)()
47 }
48}
49
50macro_rules! impl_handler {
51 ($( $t:ident ),+) => {
52 impl<'a, $( $t, )* F, O> Handler<'a, ($( $t, )*)> for F
53 where
54 F: FnOnce($( $t ),*) -> Result<O, Error>,
55 O: NoUninit,
56 $(
57 $t: HandlerContext<'a>,
58 )*
59 {
60 type Output = O;
61
62 fn call(
63 self,
64 program_id: &Pubkey,
65 accounts: &mut &'a [AccountInfo],
66 instruction_data: &mut &'a [u8],
67 ) -> Result<Self::Output, Error> {
68 paste! {
69 $(
70 let [<$t:lower>] = $t::from_entrypoint(program_id, accounts, instruction_data)?;
71 )*
72 (self)($( [<$t:lower>], )*)
73 }
74 }
75 }
76 };
77}
78
79impl_handler!(T1);
80impl_handler!(T1, T2);
81impl_handler!(T1, T2, T3);
82impl_handler!(T1, T2, T3, T4);
83impl_handler!(T1, T2, T3, T4, T5);
84impl_handler!(T1, T2, T3, T4, T5, T6);
85impl_handler!(T1, T2, T3, T4, T5, T6, T7);
86
87pub fn handle<'a, T, H>(
88 program_id: &Pubkey,
89 mut accounts: &'a [AccountInfo],
90 mut instruction_data: &'a [u8],
91 handler: H,
92) -> Result<(), Error>
93where
94 H: Handler<'a, T>,
95{
96 match handler.call(program_id, &mut accounts, &mut instruction_data) {
97 Ok(res) => {
98 if core::mem::size_of::<H::Output>() > 0 {
99 set_return_data(bytemuck::bytes_of(&res));
100 }
101
102 Ok(())
103 }
104 Err(err) => Err(err),
105 }
106}