typhoon-accounts 0.1.0-alpha.16

TODO
Documentation
use {
    super::{Account, SystemAccount, UncheckedAccount},
    crate::{
        Discriminator, FromAccountInfo, FromRaw, InterfaceAccount, ReadableAccount, RefFromBytes,
        Signer, SignerAccount, SignerCheck, WritableAccount,
    },
    pinocchio::{
        account_info::{AccountInfo, RefMut},
        program_error::ProgramError,
    },
    typhoon_errors::{Error, ErrorCode},
};

pub struct Mut<T: ReadableAccount>(pub(crate) T);

impl<'a, T> FromAccountInfo<'a> for Mut<T>
where
    T: FromAccountInfo<'a> + ReadableAccount,
{
    #[inline(always)]
    fn try_from_info(info: &'a AccountInfo) -> Result<Self, Error> {
        if !info.is_writable() {
            return Err(ErrorCode::AccountNotMutable.into());
        }

        Ok(Mut(T::try_from_info(info)?))
    }
}

impl<T> AsRef<AccountInfo> for Mut<T>
where
    T: ReadableAccount,
{
    #[inline(always)]
    fn as_ref(&self) -> &AccountInfo {
        self.0.as_ref()
    }
}

impl<'a, T> From<Mut<T>> for &'a AccountInfo
where
    T: ReadableAccount + Into<&'a AccountInfo>,
{
    #[inline(always)]
    fn from(value: Mut<T>) -> Self {
        value.0.into()
    }
}

impl<T> ReadableAccount for Mut<T>
where
    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.0.data()
    }

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

macro_rules! impl_writable {
    ($name: ident) => {
        impl WritableAccount for Mut<$name<'_>> {
            type DataMut<'a>
                = RefMut<'a, [u8]>
            where
                Self: 'a;

            #[inline(always)]
            fn mut_data<'a>(&'a self) -> Result<Self::DataMut<'a>, Error> {
                self.0.as_ref().try_borrow_mut_data().map_err(Into::into)
            }
        }
    };
}

impl_writable!(SystemAccount);
impl_writable!(UncheckedAccount);

macro_rules! impl_writable_signer {
    ($name: ident) => {
        impl<C: SignerCheck> WritableAccount for Mut<Signer<'_, $name<'_>, C>> {
            type DataMut<'a>
                = RefMut<'a, [u8]>
            where
                Self: 'a;
            #[inline(always)]
            fn mut_data<'a>(&'a self) -> Result<Self::DataMut<'a>, Error> {
                self.0.as_ref().try_borrow_mut_data().map_err(Into::into)
            }
        }
    };
}

impl_writable_signer!(SystemAccount);
impl_writable_signer!(UncheckedAccount);

impl<T, C> WritableAccount for Mut<Signer<'_, Account<'_, T>, C>>
where
    C: SignerCheck,
    T: Discriminator + RefFromBytes,
{
    type DataMut<'a>
        = RefMut<'a, T>
    where
        Self: 'a;
    #[inline(always)]
    fn mut_data<'a>(&'a self) -> Result<Self::DataMut<'a>, Error> {
        RefMut::filter_map(self.0.as_ref().try_borrow_mut_data()?, T::read_mut)
            .map_err(|_| ProgramError::InvalidAccountData.into())
    }
}

impl<T, C> WritableAccount for Mut<Signer<'_, InterfaceAccount<'_, T>, C>>
where
    C: SignerCheck,
    T: Discriminator + RefFromBytes,
{
    type DataMut<'a>
        = RefMut<'a, T>
    where
        Self: 'a;
    #[inline(always)]
    fn mut_data<'a>(&'a self) -> Result<Self::DataMut<'a>, Error> {
        RefMut::filter_map(self.0.as_ref().try_borrow_mut_data()?, T::read_mut)
            .map_err(|_| ProgramError::InvalidAccountData.into())
    }
}

impl<T: Discriminator + RefFromBytes> WritableAccount for Mut<Account<'_, T>> {
    type DataMut<'a>
        = RefMut<'a, T>
    where
        Self: 'a;

    #[inline(always)]
    fn mut_data<'a>(&'a self) -> Result<Self::DataMut<'a>, Error> {
        RefMut::filter_map(self.0.as_ref().try_borrow_mut_data()?, T::read_mut)
            .map_err(|_| ProgramError::InvalidAccountData.into())
    }
}

impl<T: Discriminator + RefFromBytes> WritableAccount for Mut<InterfaceAccount<'_, T>> {
    type DataMut<'a>
        = RefMut<'a, T>
    where
        Self: 'a;

    #[inline(always)]
    fn mut_data<'a>(&'a self) -> Result<Self::DataMut<'a>, Error> {
        RefMut::filter_map(self.0.as_ref().try_borrow_mut_data()?, T::read_mut)
            .map_err(|_| ProgramError::InvalidAccountData.into())
    }
}

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

#[doc(hidden)]
impl<'a, T> Mut<T>
where
    T: ReadableAccount + FromRaw<'a>,
{
    #[inline(always)]
    pub fn from_raw_info(info: &'a AccountInfo) -> Self {
        Mut(T::from_raw(info))
    }
}