Skip to main content

typhoon_context/
iterator.rs

1use {
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
51/// An iterator over account infos, yielding tuples of type `T` that can be constructed from
52/// the current slice of accounts. The iterator advances by consuming the accounts as each item is produced.
53pub 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}