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