use crate::accounts::account::Account;
use crate::error::ErrorCode;
use crate::{
AccountDeserialize, AccountSerialize, Accounts, AccountsClose, AccountsExit, CheckOwner, Key,
Owners, Result, ToAccountInfos, ToAccountMetas,
};
use solana_program::account_info::AccountInfo;
use solana_program::instruction::AccountMeta;
use solana_program::pubkey::Pubkey;
use solana_program::system_program;
use std::collections::{BTreeMap, BTreeSet};
use std::fmt;
use std::ops::{Deref, DerefMut};
#[derive(Clone)]
pub struct InterfaceAccount<'info, T: AccountSerialize + AccountDeserialize + Clone> {
account: Account<'info, T>,
owner: Pubkey,
}
impl<'info, T: AccountSerialize + AccountDeserialize + Clone + fmt::Debug> fmt::Debug
for InterfaceAccount<'info, 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: AccountInfo<'a>, account: T) -> Self {
let owner = *info.owner;
Self {
account: Account::new(info, account),
owner,
}
}
pub fn reload(&mut self) -> Result<()> {
self.account.reload()
}
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: &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.clone(), T::try_deserialize(&mut data)?))
}
#[inline(never)]
pub fn try_from_unchecked(info: &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.clone(),
T::try_deserialize_unchecked(&mut data)?,
))
}
}
impl<'info, T: AccountSerialize + AccountDeserialize + CheckOwner + Clone> Accounts<'info>
for InterfaceAccount<'info, T>
{
#[inline(never)]
fn try_accounts(
_program_id: &Pubkey,
accounts: &mut &[AccountInfo<'info>],
_ix_data: &[u8],
_bumps: &mut BTreeMap<String, u8>,
_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<'info, T: AccountSerialize + AccountDeserialize + Clone> ToAccountMetas
for InterfaceAccount<'info, 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<'info, T: AccountSerialize + AccountDeserialize + Clone> AsRef<T>
for InterfaceAccount<'info, T>
{
fn as_ref(&self) -> &T {
self.account.as_ref()
}
}
impl<'a, T: AccountSerialize + AccountDeserialize + Clone> Deref for InterfaceAccount<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.account.deref()
}
}
impl<'a, T: AccountSerialize + AccountDeserialize + Clone> DerefMut for InterfaceAccount<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.account.deref_mut()
}
}
impl<'info, T: AccountSerialize + AccountDeserialize + Clone> Key for InterfaceAccount<'info, T> {
fn key(&self) -> Pubkey {
self.account.key()
}
}