typhoon-accounts 0.3.0

Account types and traits
Documentation
#![no_std]

pub use {accounts::*, discriminator::*, programs::*};
use {
    solana_account_view::{AccountView, Ref, RefMut},
    solana_address::Address,
    solana_program_error::ProgramError,
    typhoon_errors::Error,
    typhoon_traits::{Accessor, DataStrategy, Discriminator, MutAccessor},
};

mod accounts;
mod discriminator;
mod programs;

pub trait FromAccountInfo<'a>: Sized {
    fn try_from_info(info: &'a AccountView) -> Result<Self, Error>;
}

pub trait ReadableAccount: AsRef<AccountView> {
    #[inline(always)]
    fn address(&self) -> &Address {
        self.as_ref().address()
    }

    #[inline(always)]
    fn owned_by(&self, owner: &Address) -> bool {
        self.as_ref().owned_by(owner)
    }

    #[inline(always)]
    fn lamports(&self) -> u64 {
        self.as_ref().lamports()
    }

    #[inline(always)]
    fn raw_data(&self) -> Result<Ref<'_, [u8]>, ProgramError> {
        self.as_ref().try_borrow()
    }
}

pub trait WritableAccount: ReadableAccount {
    #[inline(always)]
    fn assign(&self, new_owner: &Address) {
        unsafe {
            self.as_ref().assign(new_owner);
        }
    }

    #[inline(always)]
    fn resize(&self, new_len: usize) -> Result<(), Error> {
        self.as_ref().resize(new_len).map_err(Into::into)
    }

    #[inline(always)]
    fn set_lamports(&self, lamports: u64) {
        self.as_ref().set_lamports(lamports);
    }

    #[inline(always)]
    fn raw_mut_data(&self) -> Result<RefMut<'_, [u8]>, ProgramError> {
        self.as_ref().try_borrow_mut()
    }
}

pub trait SignerAccount: ReadableAccount {}

pub trait AccountData: ReadableAccount {
    type Data: Discriminator + DataStrategy;
}

pub trait ReadableAccountData: AccountData {
    #[inline(always)]
    fn data(&self) -> Result<Ref<'_, Self::Data>, ProgramError>
    where
        <Self::Data as DataStrategy>::Strategy:
            for<'a> Accessor<'a, Self::Data, Data = &'a Self::Data>,
    {
        Ref::try_map(self.as_ref().try_borrow()?, |data| {
            <<Self::Data as DataStrategy>::Strategy as Accessor<'_, Self::Data>>::access(
                &data[Self::Data::DISCRIMINATOR.len()..],
            )
        })
        .map_err(|_| ProgramError::InvalidAccountData)
    }

    #[inline(always)]
    fn data_owned(&self) -> Result<Self::Data, ProgramError>
    where
        <Self::Data as DataStrategy>::Strategy: for<'a> Accessor<'a, Self::Data, Data = Self::Data>,
    {
        self.as_ref().check_borrow()?;
        let data = unsafe { self.as_ref().borrow_unchecked() };
        <<Self::Data as DataStrategy>::Strategy as Accessor<'_, Self::Data>>::access(
            &data[Self::Data::DISCRIMINATOR.len()..],
        )
    }

    #[inline(always)]
    fn data_unchecked(
        &self,
    ) -> Result<
        <<Self::Data as DataStrategy>::Strategy as Accessor<'_, Self::Data>>::Data,
        ProgramError,
    >
    where
        <Self::Data as DataStrategy>::Strategy: for<'a> Accessor<'a, Self::Data>,
    {
        let data = unsafe { self.as_ref().borrow_unchecked() };
        <<Self::Data as DataStrategy>::Strategy as Accessor<'_, Self::Data>>::access(
            &data[Self::Data::DISCRIMINATOR.len()..],
        )
    }
}

impl<T> ReadableAccountData for T where T: AccountData {}

pub trait WritableAccountData: AccountData + WritableAccount {
    #[inline(always)]
    fn mut_data(&self) -> Result<RefMut<'_, Self::Data>, Error>
    where
        <Self::Data as DataStrategy>::Strategy:
            for<'a> MutAccessor<'a, Self::Data, Data = &'a mut Self::Data>,
    {
        RefMut::try_map(self.as_ref().try_borrow_mut()?, |data| {
            <<Self::Data as DataStrategy>::Strategy as MutAccessor<'_, Self::Data>>::access_mut(
                &mut data[Self::Data::DISCRIMINATOR.len()..],
            )
        })
        .map_err(|_| ProgramError::InvalidAccountData.into())
    }
}

impl<T> WritableAccountData for T where T: AccountData + WritableAccount {}

pub trait FromRaw<'a> {
    fn from_raw(info: &'a AccountView) -> Self;
}