typhoon_context/
iterator.rs

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