use anchor_lang::prelude::*;
use anchor_lang::ZeroCopy;
use arrayref::array_ref;
use std::cell::RefMut;
use std::{cell::Ref, mem};
pub trait AccountReader {
fn owner(&self) -> &Pubkey;
fn data(&self) -> &[u8];
}
pub trait AccountDataWriter {
fn data_as_mut_slice(&mut self) -> &mut [u8];
}
pub trait KeyedAccountReader: AccountReader {
fn key(&self) -> &Pubkey;
}
pub struct AccountInfoRef<'a, 'info: 'a> {
pub key: &'info Pubkey,
pub owner: &'info Pubkey,
pub data: Ref<'a, &'info mut [u8]>,
}
impl<'a, 'info: 'a> AccountInfoRef<'a, 'info> {
pub fn borrow(account_info: &'a AccountInfo<'info>) -> Result<Self> {
Ok(Self {
key: account_info.key,
owner: account_info.owner,
data: account_info
.data
.try_borrow()
.map_err(|_| ProgramError::AccountBorrowFailed)?,
})
}
pub fn borrow_slice(ais: &'a [AccountInfo<'info>]) -> Result<Vec<Self>> {
ais.iter().map(Self::borrow).collect()
}
}
pub struct AccountInfoRefMut<'a, 'info: 'a> {
pub key: &'info Pubkey,
pub owner: &'info Pubkey,
pub data: RefMut<'a, &'info mut [u8]>,
}
impl<'a, 'info: 'a> AccountInfoRefMut<'a, 'info> {
pub fn borrow(account_info: &'a AccountInfo<'info>) -> Result<Self> {
Ok(Self {
key: account_info.key,
owner: account_info.owner,
data: account_info
.data
.try_borrow_mut()
.map_err(|_| ProgramError::AccountBorrowFailed)?,
})
}
pub fn borrow_slice(ais: &'a [AccountInfo<'info>]) -> Result<Vec<Self>> {
ais.iter().map(Self::borrow).collect()
}
}
impl<'info, 'a> AccountReader for AccountInfoRef<'info, 'a> {
fn owner(&self) -> &Pubkey {
self.owner
}
fn data(&self) -> &[u8] {
&self.data
}
}
impl<'info, 'a> AccountReader for AccountInfoRefMut<'info, 'a> {
fn owner(&self) -> &Pubkey {
self.owner
}
fn data(&self) -> &[u8] {
&self.data
}
}
impl<'info, 'a> KeyedAccountReader for AccountInfoRef<'info, 'a> {
fn key(&self) -> &Pubkey {
self.key
}
}
impl<'info, 'a> KeyedAccountReader for AccountInfoRefMut<'info, 'a> {
fn key(&self) -> &Pubkey {
self.key
}
}
impl<'info, 'a> AccountDataWriter for AccountInfoRefMut<'info, 'a> {
fn data_as_mut_slice(&mut self) -> &mut [u8] {
&mut self.data
}
}
#[cfg(feature = "solana-sdk")]
impl<T: solana_sdk::account::ReadableAccount> AccountReader for T {
fn owner(&self) -> &Pubkey {
self.owner()
}
fn data(&self) -> &[u8] {
self.data()
}
}
#[cfg(feature = "solana-sdk")]
impl<T: solana_sdk::account::WritableAccount> AccountDataWriter for T {
fn data_as_mut_slice(&mut self) -> &mut [u8] {
self.data_as_mut_slice()
}
}
#[cfg(feature = "solana-sdk")]
#[derive(Clone)]
pub struct KeyedAccount {
pub key: Pubkey,
pub account: solana_sdk::account::Account,
}
#[cfg(feature = "solana-sdk")]
impl AccountReader for KeyedAccount {
fn owner(&self) -> &Pubkey {
self.account.owner()
}
fn data(&self) -> &[u8] {
self.account.data()
}
}
#[cfg(feature = "solana-sdk")]
impl KeyedAccountReader for KeyedAccount {
fn key(&self) -> &Pubkey {
&self.key
}
}
#[cfg(feature = "solana-sdk")]
#[derive(Clone)]
pub struct KeyedAccountSharedData {
pub key: Pubkey,
pub data: solana_sdk::account::AccountSharedData,
}
#[cfg(feature = "solana-sdk")]
impl KeyedAccountSharedData {
pub fn new(key: Pubkey, data: solana_sdk::account::AccountSharedData) -> Self {
Self { key, data }
}
}
#[cfg(feature = "solana-sdk")]
impl AccountReader for KeyedAccountSharedData {
fn owner(&self) -> &Pubkey {
AccountReader::owner(&self.data)
}
fn data(&self) -> &[u8] {
AccountReader::data(&self.data)
}
}
#[cfg(feature = "solana-sdk")]
impl KeyedAccountReader for KeyedAccountSharedData {
fn key(&self) -> &Pubkey {
&self.key
}
}
pub trait LoadZeroCopy {
fn load<T: ZeroCopy + Owner>(&self) -> Result<&T>;
fn load_fully_unchecked<T: ZeroCopy + Owner>(&self) -> Result<&T>;
}
pub trait LoadMutZeroCopy {
fn load_mut<T: ZeroCopy + Owner>(&mut self) -> Result<&mut T>;
fn load_mut_fully_unchecked<T: ZeroCopy + Owner>(&mut self) -> Result<&mut T>;
}
pub trait LoadZeroCopyRef {
fn load<T: ZeroCopy + Owner>(&self) -> Result<Ref<T>>;
fn load_fully_unchecked<T: ZeroCopy + Owner>(&self) -> Result<Ref<T>>;
}
pub trait LoadMutZeroCopyRef {
fn load_mut<T: ZeroCopy + Owner>(&self) -> Result<RefMut<T>>;
fn load_mut_fully_unchecked<T: ZeroCopy + Owner>(&self) -> Result<RefMut<T>>;
}
impl<A: AccountReader> LoadZeroCopy for A {
fn load<T: ZeroCopy + Owner>(&self) -> Result<&T> {
if self.owner() != &T::owner() {
return Err(ErrorCode::AccountOwnedByWrongProgram.into());
}
let data = self.data();
if data.len() < 8 {
return Err(ErrorCode::AccountDiscriminatorNotFound.into());
}
let disc_bytes = array_ref![data, 0, 8];
if disc_bytes != &T::discriminator() {
return Err(ErrorCode::AccountDiscriminatorMismatch.into());
}
Ok(bytemuck::from_bytes(&data[8..mem::size_of::<T>() + 8]))
}
fn load_fully_unchecked<T: ZeroCopy + Owner>(&self) -> Result<&T> {
Ok(bytemuck::from_bytes(
&self.data()[8..mem::size_of::<T>() + 8],
))
}
}
impl<A: AccountReader + AccountDataWriter> LoadMutZeroCopy for A {
fn load_mut<T: ZeroCopy + Owner>(&mut self) -> Result<&mut T> {
if self.owner() != &T::owner() {
return Err(ErrorCode::AccountOwnedByWrongProgram.into());
}
let data = self.data_as_mut_slice();
if data.len() < 8 {
return Err(ErrorCode::AccountDiscriminatorNotFound.into());
}
let disc_bytes = array_ref![data, 0, 8];
if disc_bytes != &T::discriminator() {
return Err(ErrorCode::AccountDiscriminatorMismatch.into());
}
Ok(bytemuck::from_bytes_mut(
&mut data[8..mem::size_of::<T>() + 8],
))
}
fn load_mut_fully_unchecked<T: ZeroCopy + Owner>(&mut self) -> Result<&mut T> {
Ok(bytemuck::from_bytes_mut(
&mut self.data_as_mut_slice()[8..mem::size_of::<T>() + 8],
))
}
}
impl<'info> LoadZeroCopyRef for AccountInfo<'info> {
fn load<T: ZeroCopy + Owner>(&self) -> Result<Ref<T>> {
if self.owner != &T::owner() {
return Err(ErrorCode::AccountOwnedByWrongProgram.into());
}
let data = self.try_borrow_data()?;
if data.len() < 8 {
return Err(ErrorCode::AccountDiscriminatorNotFound.into());
}
let disc_bytes = array_ref![data, 0, 8];
if disc_bytes != &T::discriminator() {
return Err(ErrorCode::AccountDiscriminatorMismatch.into());
}
Ok(Ref::map(data, |data| {
bytemuck::from_bytes(&data[8..mem::size_of::<T>() + 8])
}))
}
fn load_fully_unchecked<T: ZeroCopy + Owner>(&self) -> Result<Ref<T>> {
let data = self.try_borrow_data()?;
Ok(Ref::map(data, |data| {
bytemuck::from_bytes(&data[8..mem::size_of::<T>() + 8])
}))
}
}
impl<'info> LoadMutZeroCopyRef for AccountInfo<'info> {
fn load_mut<T: ZeroCopy + Owner>(&self) -> Result<RefMut<T>> {
if self.owner != &T::owner() {
return Err(ErrorCode::AccountOwnedByWrongProgram.into());
}
let data = self.try_borrow_mut_data()?;
if data.len() < 8 {
return Err(ErrorCode::AccountDiscriminatorNotFound.into());
}
let disc_bytes = array_ref![data, 0, 8];
if disc_bytes != &T::discriminator() {
return Err(ErrorCode::AccountDiscriminatorMismatch.into());
}
Ok(RefMut::map(data, |data| {
bytemuck::from_bytes_mut(&mut data[8..mem::size_of::<T>() + 8])
}))
}
fn load_mut_fully_unchecked<T: ZeroCopy + Owner>(&self) -> Result<RefMut<T>> {
let data = self.try_borrow_mut_data()?;
Ok(RefMut::map(data, |data| {
bytemuck::from_bytes_mut(&mut data[8..mem::size_of::<T>() + 8])
}))
}
}