use {
crate::{
accounts::account::Account,
error::ErrorCode,
solana_program::{
account_info::AccountInfo, instruction::AccountMeta, pubkey::Pubkey, system_program,
},
AccountDeserialize, AccountSerialize, Accounts, AccountsClose, AccountsExit, CheckOwner,
Key, Owners, Result, ToAccountInfos, ToAccountMetas,
},
std::{
collections::BTreeSet,
fmt,
ops::{Deref, DerefMut},
},
};
#[derive(Clone)]
pub struct InterfaceAccount<'info, T: AccountSerialize + AccountDeserialize + Clone> {
account: Account<'info, T>,
owner: Pubkey,
}
impl<T: AccountSerialize + AccountDeserialize + Clone + fmt::Debug> fmt::Debug
for InterfaceAccount<'_, T>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.account.fmt_with_name("InterfaceAccount", f)
}
}
impl<'a, T: AccountSerialize + AccountDeserialize + Clone> InterfaceAccount<'a, T> {
fn new(info: &'a AccountInfo<'a>, account: T) -> Self {
let owner = *info.owner;
Self {
account: Account::new(info, account),
owner,
}
}
pub fn into_inner(self) -> T {
self.account.into_inner()
}
pub fn set_inner(&mut self, inner: T) {
self.account.set_inner(inner);
}
}
impl<'a, T: AccountSerialize + AccountDeserialize + CheckOwner + Clone> InterfaceAccount<'a, T> {
#[inline(never)]
pub fn try_from(info: &'a AccountInfo<'a>) -> Result<Self> {
if info.owner == &system_program::ID && info.lamports() == 0 {
return Err(ErrorCode::AccountNotInitialized.into());
}
T::check_owner(info.owner)?;
let mut data: &[u8] = &info.try_borrow_data()?;
Ok(Self::new(info, T::try_deserialize(&mut data)?))
}
#[inline(never)]
pub fn try_from_unchecked(info: &'a AccountInfo<'a>) -> Result<Self> {
if info.owner == &system_program::ID && info.lamports() == 0 {
return Err(ErrorCode::AccountNotInitialized.into());
}
T::check_owner(info.owner)?;
let mut data: &[u8] = &info.try_borrow_data()?;
Ok(Self::new(info, T::try_deserialize_unchecked(&mut data)?))
}
pub fn reload(&mut self) -> Result<()> {
let info: &AccountInfo = self.account.as_ref();
T::check_owner(info.owner)?;
self.account.set_inner({
let mut data: &[u8] = &info.try_borrow_data()?;
T::try_deserialize(&mut data)?
});
Ok(())
}
}
impl<'info, B, T: AccountSerialize + AccountDeserialize + CheckOwner + Clone> Accounts<'info, B>
for InterfaceAccount<'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<'info, T: AccountSerialize + AccountDeserialize + Owners + Clone> AccountsExit<'info>
for InterfaceAccount<'info, T>
{
fn exit(&self, program_id: &Pubkey) -> Result<()> {
self.account
.exit_with_expected_owner(&self.owner, program_id)
}
}
impl<'info, T: AccountSerialize + AccountDeserialize + Clone> AccountsClose<'info>
for InterfaceAccount<'info, T>
{
fn close(&self, sol_destination: AccountInfo<'info>) -> Result<()> {
self.account.close(sol_destination)
}
}
impl<T: AccountSerialize + AccountDeserialize + Clone> ToAccountMetas for InterfaceAccount<'_, T> {
fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
self.account.to_account_metas(is_signer)
}
}
impl<'info, T: AccountSerialize + AccountDeserialize + Clone> ToAccountInfos<'info>
for InterfaceAccount<'info, T>
{
fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
self.account.to_account_infos()
}
}
impl<'info, T: AccountSerialize + AccountDeserialize + Clone> AsRef<AccountInfo<'info>>
for InterfaceAccount<'info, T>
{
fn as_ref(&self) -> &AccountInfo<'info> {
self.account.as_ref()
}
}
impl<T: AccountSerialize + AccountDeserialize + Clone> AsRef<T> for InterfaceAccount<'_, T> {
fn as_ref(&self) -> &T {
self.account.as_ref()
}
}
impl<T: AccountSerialize + AccountDeserialize + Clone> Deref for InterfaceAccount<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.account.deref()
}
}
impl<T: AccountSerialize + AccountDeserialize + Clone> DerefMut for InterfaceAccount<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.account.deref_mut()
}
}
impl<T: AccountSerialize + AccountDeserialize + Clone> Key for InterfaceAccount<'_, T> {
fn key(&self) -> Pubkey {
self.account.key()
}
}