use {
crate::HandlerContext, core::marker::PhantomData, pastey::paste,
solana_account_view::AccountView, solana_address::Address, solana_program_error::ProgramError,
typhoon_accounts::FromAccountInfo, typhoon_errors::Error,
};
trait FromInfos<'a>: Sized {
fn from_infos(accounts: &mut &'a [AccountView]) -> Result<Self, Error>;
}
macro_rules! impl_from_infos {
($($t:ident),+) => {
impl<'a, $($t),+> FromInfos<'a> for ($($t),+) where $($t: FromAccountInfo<'a>),+ {
fn from_infos(accounts: &mut &'a [AccountView]) -> Result<Self, Error> {
paste! {
let [$( [<acc_ $t:lower>], )+ rem @ ..] = *accounts else {
return Err(Error::new(ProgramError::NotEnoughAccountKeys));
};
}
paste! {
$( let [<val_ $t:lower>] = $t::try_from_info([<acc_ $t:lower>])?; )+
*accounts = rem;
Ok(( $( [<val_ $t:lower>] ),+ ))
}
}
}
};
}
impl_from_infos!(T1, T2);
impl_from_infos!(T1, T2, T3);
impl_from_infos!(T1, T2, T3, T4);
impl_from_infos!(T1, T2, T3, T4, T5);
impl<'a, T: FromAccountInfo<'a>> FromInfos<'a> for (T,) {
fn from_infos(accounts: &mut &'a [AccountView]) -> Result<Self, Error> {
let [acc, rem @ ..] = *accounts else {
return Err(Error::new(ProgramError::NotEnoughAccountKeys));
};
let acc = T::try_from_info(acc)?;
*accounts = rem;
Ok((acc,))
}
}
pub struct AccountIter<'a, T> {
accounts: &'a [AccountView],
_phantom: PhantomData<T>,
}
impl<'b, T> HandlerContext<'_, 'b, '_> for AccountIter<'b, T> {
fn from_entrypoint(
_program_id: &Address,
accounts: &mut &'b [AccountView],
_instruction_data: &mut &[u8],
) -> Result<Self, typhoon_errors::Error> {
Ok(AccountIter {
accounts,
_phantom: PhantomData,
})
}
}
impl<'a, T> Iterator for AccountIter<'a, T>
where
T: FromInfos<'a>,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
T::from_infos(&mut self.accounts).ok()
}
}