Skip to main content

typhoon_accounts/
lib.rs

1#![no_std]
2
3pub use {accounts::*, discriminator::*, programs::*};
4use {
5    solana_account_view::{AccountView, Ref, RefMut},
6    solana_address::Address,
7    solana_program_error::ProgramError,
8    typhoon_errors::Error,
9    typhoon_traits::{Accessor, DataStrategy, Discriminator, MutAccessor},
10};
11
12mod accounts;
13mod discriminator;
14mod programs;
15
16pub trait FromAccountInfo<'a>: Sized {
17    fn try_from_info(info: &'a AccountView) -> Result<Self, Error>;
18}
19
20pub trait ReadableAccount: AsRef<AccountView> {
21    #[inline(always)]
22    fn address(&self) -> &Address {
23        self.as_ref().address()
24    }
25
26    #[inline(always)]
27    fn owned_by(&self, owner: &Address) -> bool {
28        self.as_ref().owned_by(owner)
29    }
30
31    #[inline(always)]
32    fn lamports(&self) -> u64 {
33        self.as_ref().lamports()
34    }
35
36    #[inline(always)]
37    fn raw_data(&self) -> Result<Ref<'_, [u8]>, ProgramError> {
38        self.as_ref().try_borrow()
39    }
40}
41
42pub trait WritableAccount: ReadableAccount {
43    #[inline(always)]
44    fn assign(&self, new_owner: &Address) {
45        unsafe {
46            self.as_ref().assign(new_owner);
47        }
48    }
49
50    #[inline(always)]
51    fn resize(&self, new_len: usize) -> Result<(), Error> {
52        self.as_ref().resize(new_len).map_err(Into::into)
53    }
54
55    #[inline(always)]
56    fn set_lamports(&self, lamports: u64) {
57        self.as_ref().set_lamports(lamports);
58    }
59
60    #[inline(always)]
61    fn raw_mut_data(&self) -> Result<RefMut<'_, [u8]>, ProgramError> {
62        self.as_ref().try_borrow_mut()
63    }
64}
65
66pub trait SignerAccount: ReadableAccount {}
67
68pub trait AccountData: ReadableAccount {
69    type Data: Discriminator + DataStrategy;
70}
71
72pub trait ReadableAccountData: AccountData {
73    #[inline(always)]
74    fn data(&self) -> Result<Ref<'_, Self::Data>, ProgramError>
75    where
76        <Self::Data as DataStrategy>::Strategy:
77            for<'a> Accessor<'a, Self::Data, Data = &'a Self::Data>,
78    {
79        Ref::try_map(self.as_ref().try_borrow()?, |data| {
80            <<Self::Data as DataStrategy>::Strategy as Accessor<'_, Self::Data>>::access(
81                &data[Self::Data::DISCRIMINATOR.len()..],
82            )
83        })
84        .map_err(|_| ProgramError::InvalidAccountData)
85    }
86
87    #[inline(always)]
88    fn data_owned(&self) -> Result<Self::Data, ProgramError>
89    where
90        <Self::Data as DataStrategy>::Strategy: for<'a> Accessor<'a, Self::Data, Data = Self::Data>,
91    {
92        self.as_ref().check_borrow()?;
93        let data = unsafe { self.as_ref().borrow_unchecked() };
94        <<Self::Data as DataStrategy>::Strategy as Accessor<'_, Self::Data>>::access(
95            &data[Self::Data::DISCRIMINATOR.len()..],
96        )
97    }
98
99    #[inline(always)]
100    fn data_unchecked(
101        &self,
102    ) -> Result<
103        <<Self::Data as DataStrategy>::Strategy as Accessor<'_, Self::Data>>::Data,
104        ProgramError,
105    >
106    where
107        <Self::Data as DataStrategy>::Strategy: for<'a> Accessor<'a, Self::Data>,
108    {
109        let data = unsafe { self.as_ref().borrow_unchecked() };
110        <<Self::Data as DataStrategy>::Strategy as Accessor<'_, Self::Data>>::access(
111            &data[Self::Data::DISCRIMINATOR.len()..],
112        )
113    }
114}
115
116impl<T> ReadableAccountData for T where T: AccountData {}
117
118pub trait WritableAccountData: AccountData + WritableAccount {
119    #[inline(always)]
120    fn mut_data(&self) -> Result<RefMut<'_, Self::Data>, Error>
121    where
122        <Self::Data as DataStrategy>::Strategy:
123            for<'a> MutAccessor<'a, Self::Data, Data = &'a mut Self::Data>,
124    {
125        RefMut::try_map(self.as_ref().try_borrow_mut()?, |data| {
126            <<Self::Data as DataStrategy>::Strategy as MutAccessor<'_, Self::Data>>::access_mut(
127                &mut data[Self::Data::DISCRIMINATOR.len()..],
128            )
129        })
130        .map_err(|_| ProgramError::InvalidAccountData.into())
131    }
132}
133
134impl<T> WritableAccountData for T where T: AccountData + WritableAccount {}
135
136pub trait FromRaw<'a> {
137    fn from_raw(info: &'a AccountView) -> Self;
138}