typhoon_context/
lib.rs

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}