typhoon_context/
lib.rs

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}