Skip to main content

typhoon_accounts/accounts/
program.rs

1use {
2    crate::{FromAccountInfo, ReadableAccount},
3    core::marker::PhantomData,
4    pinocchio::hint::unlikely,
5    solana_account_view::{AccountView, Ref},
6    solana_address::address_eq,
7    solana_program_error::ProgramError,
8    typhoon_errors::Error,
9    typhoon_traits::ProgramId,
10};
11
12///
13/// Checks:
14/// * `account_info.key == expected_program`
15/// * `account_info.executable == true`
16pub struct Program<'a, T> {
17    info: &'a AccountView,
18    _phantom: PhantomData<T>,
19}
20
21impl<'a, T> FromAccountInfo<'a> for Program<'a, T>
22where
23    T: ProgramId,
24{
25    #[inline]
26    fn try_from_info(info: &'a AccountView) -> Result<Self, Error> {
27        // Optimized program ID check using fast memory comparison
28        if unlikely(!address_eq(info.address(), &T::ID)) {
29            return Err(ProgramError::IncorrectProgramId.into());
30        }
31
32        if !info.executable() {
33            return Err(ProgramError::InvalidAccountOwner.into());
34        }
35
36        Ok(Program {
37            info,
38            _phantom: PhantomData,
39        })
40    }
41}
42
43impl<'a, T> From<Program<'a, T>> for &'a AccountView {
44    #[inline(always)]
45    fn from(value: Program<'a, T>) -> Self {
46        value.info
47    }
48}
49
50impl<T> AsRef<AccountView> for Program<'_, T> {
51    #[inline(always)]
52    fn as_ref(&self) -> &AccountView {
53        self.info
54    }
55}
56
57impl<T> ReadableAccount for Program<'_, T> {
58    type DataUnchecked = [u8];
59    type Data<'a>
60        = Ref<'a, [u8]>
61    where
62        Self: 'a;
63
64    #[inline(always)]
65    fn data<'a>(&'a self) -> Result<Self::Data<'a>, Error> {
66        self.info.try_borrow().map_err(Into::into)
67    }
68
69    #[inline]
70    fn data_unchecked(&self) -> Result<&Self::DataUnchecked, Error> {
71        Ok(unsafe { self.info.borrow_unchecked() })
72    }
73}