typhoon_context/
iterator.rs1use {
2 crate::HandlerContext,
3 core::marker::PhantomData,
4 paste::paste,
5 pinocchio::{account_info::AccountInfo, program_error::ProgramError},
6 typhoon_accounts::FromAccountInfo,
7 typhoon_errors::Error,
8};
9
10trait FromInfos<'a>: Sized {
11 fn from_infos(accounts: &mut &'a [AccountInfo]) -> Result<Self, Error>;
12}
13
14macro_rules! impl_from_infos {
15 ($($t:ident),+) => {
16 impl<'a, $($t),+> FromInfos<'a> for ($($t),+) where $($t: FromAccountInfo<'a>),+ {
17 fn from_infos(accounts: &mut &'a [AccountInfo]) -> Result<Self, Error> {
18 paste! {
19 let [$( [<acc_ $t:lower>], )+ rem @ ..] = *accounts else {
20 return Err(Error::new(ProgramError::NotEnoughAccountKeys));
21 };
22 }
23
24 paste! {
25 $( let [<val_ $t:lower>] = $t::try_from_info([<acc_ $t:lower>])?; )+
26
27 *accounts = rem;
28
29 Ok(( $( [<val_ $t:lower>] ),+ ))
30 }
31 }
32 }
33 };
34}
35
36impl_from_infos!(T1, T2);
37impl_from_infos!(T1, T2, T3);
38impl_from_infos!(T1, T2, T3, T4);
39impl_from_infos!(T1, T2, T3, T4, T5);
40
41impl<'a, T: FromAccountInfo<'a>> FromInfos<'a> for (T,) {
42 fn from_infos(accounts: &mut &'a [AccountInfo]) -> Result<Self, Error> {
43 let [acc, rem @ ..] = *accounts else {
44 return Err(Error::new(ProgramError::NotEnoughAccountKeys));
45 };
46
47 let acc = T::try_from_info(acc)?;
48 *accounts = rem;
49
50 Ok((acc,))
51 }
52}
53
54pub struct AccountIter<'a, T> {
57 accounts: &'a [AccountInfo],
58 _phantom: PhantomData<T>,
59}
60
61impl<'b, T> HandlerContext<'_, 'b, '_> for AccountIter<'b, T> {
62 fn from_entrypoint(
63 _program_id: &pinocchio::pubkey::Pubkey,
64 accounts: &mut &'b [AccountInfo],
65 _instruction_data: &mut &[u8],
66 ) -> Result<Self, typhoon_errors::Error> {
67 Ok(AccountIter {
68 accounts,
69 _phantom: PhantomData,
70 })
71 }
72}
73
74impl<'a, T> Iterator for AccountIter<'a, T>
75where
76 T: FromInfos<'a>,
77{
78 type Item = T;
79
80 fn next(&mut self) -> Option<Self::Item> {
81 T::from_infos(&mut self.accounts).ok()
82 }
83}