use core::marker::PhantomData;
use crate::account::AccountView;
use crate::address::Address;
#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct Signer<'info> {
inner: &'info AccountView,
}
impl<'info> Signer<'info> {
#[inline(always)]
pub unsafe fn new_unchecked(view: &'info AccountView) -> Self {
Self { inner: view }
}
#[inline]
pub fn try_new(view: &'info AccountView) -> Result<Self, crate::error::ProgramError> {
view.check_signer()?;
Ok(Self { inner: view })
}
#[inline(always)]
pub fn as_account(&self) -> &'info AccountView {
self.inner
}
#[inline(always)]
pub fn key(&self) -> &Address {
self.inner.address()
}
}
impl<'info> core::ops::Deref for Signer<'info> {
type Target = AccountView;
#[inline(always)]
fn deref(&self) -> &AccountView {
self.inner
}
}
#[repr(transparent)]
pub struct Account<'info, T: crate::layout::LayoutContract> {
inner: &'info AccountView,
_ty: PhantomData<T>,
}
impl<'info, T: crate::layout::LayoutContract> Clone for Account<'info, T> {
fn clone(&self) -> Self {
*self
}
}
impl<'info, T: crate::layout::LayoutContract> Copy for Account<'info, T> {}
impl<'info, T: crate::layout::LayoutContract> Account<'info, T> {
#[inline(always)]
pub unsafe fn new_unchecked(view: &'info AccountView) -> Self {
Self {
inner: view,
_ty: PhantomData,
}
}
#[inline]
pub fn try_new(
view: &'info AccountView,
owner: &Address,
) -> Result<Self, crate::error::ProgramError> {
view.check_owned_by(owner)?;
let _ = view.load::<T>()?;
Ok(Self {
inner: view,
_ty: PhantomData,
})
}
#[inline(always)]
pub fn as_account(&self) -> &'info AccountView {
self.inner
}
#[inline(always)]
pub fn load(&self) -> Result<crate::borrow::Ref<'_, T>, crate::error::ProgramError> {
self.inner.load::<T>()
}
#[inline(always)]
pub fn load_mut(&self) -> Result<crate::borrow::RefMut<'_, T>, crate::error::ProgramError> {
self.inner.load_mut::<T>()
}
}
#[repr(transparent)]
pub struct InitAccount<'info, T: crate::layout::LayoutContract> {
inner: &'info AccountView,
_ty: PhantomData<T>,
}
impl<'info, T: crate::layout::LayoutContract> Clone for InitAccount<'info, T> {
fn clone(&self) -> Self {
*self
}
}
impl<'info, T: crate::layout::LayoutContract> Copy for InitAccount<'info, T> {}
impl<'info, T: crate::layout::LayoutContract> InitAccount<'info, T> {
#[inline(always)]
pub unsafe fn new_unchecked(view: &'info AccountView) -> Self {
Self {
inner: view,
_ty: PhantomData,
}
}
#[inline(always)]
pub fn as_account(&self) -> &'info AccountView {
self.inner
}
#[inline(always)]
pub fn load_after_init(&self) -> Result<crate::borrow::RefMut<'_, T>, crate::error::ProgramError> {
self.inner.load_mut::<T>()
}
}
#[repr(transparent)]
pub struct Program<'info, P: ProgramId> {
inner: &'info AccountView,
_ty: PhantomData<P>,
}
impl<'info, P: ProgramId> Clone for Program<'info, P> {
fn clone(&self) -> Self {
*self
}
}
impl<'info, P: ProgramId> Copy for Program<'info, P> {}
impl<'info, P: ProgramId> Program<'info, P> {
#[inline]
pub fn try_new(view: &'info AccountView) -> Result<Self, crate::error::ProgramError> {
if view.address() != &P::ID {
return Err(crate::error::ProgramError::IncorrectProgramId);
}
if !view.executable() {
return Err(crate::error::ProgramError::InvalidAccountData);
}
Ok(Self {
inner: view,
_ty: PhantomData,
})
}
#[inline(always)]
pub fn as_account(&self) -> &'info AccountView {
self.inner
}
}
pub trait ProgramId: 'static {
const ID: Address;
}
pub struct SystemId;
impl ProgramId for SystemId {
const ID: Address = Address::new_from_array([0u8; 32]);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn signer_wrapper_is_pointer_sized_zero_cost() {
assert_eq!(
core::mem::size_of::<Signer<'static>>(),
core::mem::size_of::<&'static AccountView>()
);
}
#[test]
fn system_program_id_is_all_zero() {
let sys = SystemId::ID;
assert_eq!(sys.as_array(), &[0u8; 32]);
}
}