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