typhoon-accounts 0.3.0

Account types and traits
Documentation
use {
    crate::{
        AccountData, FromAccountInfo, FromRaw, ReadableAccount, SignerAccount, UncheckedAccount,
    },
    core::{marker::PhantomData, ops::Deref},
    solana_account_view::AccountView,
    typhoon_errors::{Error, ErrorCode},
};

pub type UncheckedSigner<'a, T> = Signer<'a, T, NoCheck>;

pub trait SignerCheck {
    fn check(_info: &AccountView) -> Result<(), Error> {
        Ok(())
    }
}

pub struct Check;

impl SignerCheck for Check {
    fn check(info: &AccountView) -> Result<(), Error> {
        if info.is_signer() {
            Ok(())
        } else {
            Err(ErrorCode::AccountNotSigner.into())
        }
    }
}

pub struct NoCheck;

impl SignerCheck for NoCheck {}

pub struct Signer<'a, T = UncheckedAccount<'a>, C = Check>
where
    T: ReadableAccount,
    C: SignerCheck,
{
    pub(crate) acc: T,
    _phantom: PhantomData<&'a C>,
}

impl<'a, T, C> FromAccountInfo<'a> for Signer<'a, T, C>
where
    C: SignerCheck,
    T: ReadableAccount + FromAccountInfo<'a>,
{
    #[inline(always)]
    fn try_from_info(info: &'a AccountView) -> Result<Self, Error> {
        C::check(info)?;

        Ok(Signer {
            acc: T::try_from_info(info)?,
            _phantom: PhantomData,
        })
    }
}

impl<'a, T, C> From<Signer<'a, T, C>> for &'a AccountView
where
    C: SignerCheck,
    T: ReadableAccount + Into<&'a AccountView>,
{
    #[inline(always)]
    fn from(value: Signer<'a, T, C>) -> Self {
        value.acc.into()
    }
}

impl<T, C> AsRef<AccountView> for Signer<'_, T, C>
where
    C: SignerCheck,
    T: ReadableAccount,
{
    #[inline(always)]
    fn as_ref(&self) -> &AccountView {
        self.acc.as_ref()
    }
}

impl<T, C> SignerAccount for Signer<'_, T, C>
where
    T: ReadableAccount,
    C: SignerCheck,
{
}

impl<T, C> Deref for Signer<'_, T, C>
where
    C: SignerCheck,
    T: ReadableAccount,
{
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.acc
    }
}

impl<T, C> ReadableAccount for Signer<'_, T, C>
where
    C: SignerCheck,
    T: ReadableAccount,
{
}

impl<T, C> AccountData for Signer<'_, T, C>
where
    C: SignerCheck,
    T: AccountData + ReadableAccount,
{
    type Data = T::Data;
}

impl<'a, T, C> FromRaw<'a> for Signer<'a, T, C>
where
    T: ReadableAccount + FromRaw<'a>,
    C: SignerCheck,
{
    fn from_raw(info: &'a AccountView) -> Self {
        Self {
            acc: T::from_raw(info),
            _phantom: PhantomData,
        }
    }
}