use {
crate::{
accounts::program::Program,
error::{Error, ErrorCode},
solana_program::{account_info::AccountInfo, instruction::AccountMeta, pubkey::Pubkey},
AccountDeserialize, Accounts, AccountsExit, CheckId, Key, Result, ToAccountInfos,
ToAccountMetas,
},
std::{collections::BTreeSet, ops::Deref},
};
#[derive(Clone)]
pub struct Interface<'info, T>(Program<'info, T>);
impl<'a, T> Interface<'a, T> {
pub(crate) fn new(info: &'a AccountInfo<'a>) -> Self {
Self(Program::new(info))
}
pub fn programdata_address(&self) -> Result<Option<Pubkey>> {
self.0.programdata_address()
}
}
impl<'a, T: CheckId> TryFrom<&'a AccountInfo<'a>> for Interface<'a, T> {
type Error = Error;
fn try_from(info: &'a AccountInfo<'a>) -> Result<Self> {
T::check_id(info.key)?;
if !info.executable {
return Err(ErrorCode::InvalidProgramExecutable.into());
}
Ok(Self::new(info))
}
}
impl<'info, T> Deref for Interface<'info, T> {
type Target = AccountInfo<'info>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'info, T> AsRef<AccountInfo<'info>> for Interface<'info, T> {
fn as_ref(&self) -> &AccountInfo<'info> {
&self.0
}
}
impl<'info, B, T: CheckId> Accounts<'info, B> for Interface<'info, T> {
#[inline(never)]
fn try_accounts(
_program_id: &Pubkey,
accounts: &mut &'info [AccountInfo<'info>],
_ix_data: &[u8],
_bumps: &mut B,
_reallocs: &mut BTreeSet<Pubkey>,
) -> Result<Self> {
if accounts.is_empty() {
return Err(ErrorCode::AccountNotEnoughKeys.into());
}
let account = &accounts[0];
*accounts = &accounts[1..];
Self::try_from(account)
}
}
impl<T> ToAccountMetas for Interface<'_, T> {
fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
self.0.to_account_metas(is_signer)
}
}
impl<'info, T> ToAccountInfos<'info> for Interface<'info, T> {
fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
self.0.to_account_infos()
}
}
impl<'info, T: AccountDeserialize> AccountsExit<'info> for Interface<'info, T> {}
impl<T: AccountDeserialize> Key for Interface<'_, T> {
fn key(&self) -> Pubkey {
self.0.key()
}
}