typhoon-accounts 0.1.0-alpha.16

TODO
Documentation
use {
    crate::{FromAccountInfo, FromRaw, ReadableAccount, SignerAccount, UncheckedAccount},
    core::{marker::PhantomData, ops::Deref},
    pinocchio::account_info::AccountInfo,
    typhoon_errors::{Error, ErrorCode},
};

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

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

pub struct Check;

impl SignerCheck for Check {
    fn check(info: &AccountInfo) -> 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 AccountInfo) -> 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 AccountInfo
where
    C: SignerCheck,
    T: ReadableAccount + Into<&'a AccountInfo>,
{
    #[inline(always)]
    fn from(value: Signer<'a, T, C>) -> Self {
        value.acc.into()
    }
}

impl<T, C> AsRef<AccountInfo> for Signer<'_, T, C>
where
    C: SignerCheck,
    T: ReadableAccount,
{
    #[inline(always)]
    fn as_ref(&self) -> &AccountInfo {
        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,
{
    type DataUnchecked = T::DataUnchecked;
    type Data<'a>
        = T::Data<'a>
    where
        Self: 'a;

    #[inline(always)]
    fn data<'a>(&'a self) -> Result<Self::Data<'a>, Error> {
        self.acc.data()
    }

    #[inline]
    fn data_unchecked(&self) -> Result<&Self::DataUnchecked, Error> {
        self.acc.data_unchecked()
    }
}

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