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