2022-03-16 08:23:06 -07:00
|
|
|
use anchor_lang::prelude::*;
|
|
|
|
use anchor_lang::ZeroCopy;
|
|
|
|
use arrayref::array_ref;
|
2022-03-21 12:29:28 -07:00
|
|
|
use std::cell::RefMut;
|
2022-03-16 08:23:06 -07:00
|
|
|
use std::{cell::Ref, mem};
|
|
|
|
|
2022-03-04 05:30:53 -08:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! zip {
|
|
|
|
($x: expr) => ($x);
|
|
|
|
($x: expr, $($y: expr), +) => (
|
|
|
|
$x.zip(
|
|
|
|
zip!($($y), +))
|
|
|
|
)
|
2022-03-02 21:15:28 -08:00
|
|
|
}
|
2022-03-04 05:30:53 -08:00
|
|
|
pub(crate) use zip;
|
2022-03-11 00:57:30 -08:00
|
|
|
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! checked_math {
|
|
|
|
($x: expr) => {
|
2022-03-14 04:45:32 -07:00
|
|
|
checked_math::checked_math!($x).unwrap_or_else(|| panic!("math error"))
|
2022-03-11 00:57:30 -08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
pub(crate) use checked_math;
|
2022-03-16 08:23:06 -07:00
|
|
|
|
|
|
|
pub trait LoadZeroCopy {
|
|
|
|
/// Using AccountLoader forces a AccountInfo.clone() and then binds the loaded
|
|
|
|
/// lifetime to the AccountLoader's lifetime. This function avoids both.
|
|
|
|
/// It checks the account owner and discriminator, then casts the data.
|
|
|
|
fn load<T: ZeroCopy + Owner>(&self) -> Result<Ref<T>>;
|
|
|
|
|
2022-03-21 12:29:28 -07:00
|
|
|
/// Same as load(), but mut
|
|
|
|
fn load_mut<T: ZeroCopy + Owner>(&self) -> Result<RefMut<T>>;
|
|
|
|
|
2022-03-16 08:23:06 -07:00
|
|
|
/// Same as load(), but doesn't check the discriminator.
|
|
|
|
fn load_unchecked<T: ZeroCopy + Owner>(&self) -> Result<Ref<T>>;
|
2022-03-21 12:29:28 -07:00
|
|
|
|
|
|
|
/// Same as load_unchecked(), but mut
|
|
|
|
fn load_unchecked_mut<T: ZeroCopy + Owner>(&self) -> Result<RefMut<T>>;
|
2022-03-16 08:23:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'info> LoadZeroCopy for AccountInfo<'info> {
|
2022-03-21 12:29:28 -07:00
|
|
|
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()?;
|
|
|
|
|
|
|
|
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])
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
2022-03-16 08:23:06 -07:00
|
|
|
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()?;
|
|
|
|
|
|
|
|
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])
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
2022-03-21 12:29:28 -07:00
|
|
|
fn load_unchecked_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()?;
|
|
|
|
|
|
|
|
Ok(RefMut::map(data, |data| {
|
|
|
|
bytemuck::from_bytes_mut(&mut data[8..mem::size_of::<T>() + 8])
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
2022-03-16 08:23:06 -07:00
|
|
|
fn load_unchecked<T: ZeroCopy + Owner>(&self) -> Result<Ref<T>> {
|
|
|
|
if self.owner != &T::owner() {
|
|
|
|
return Err(ErrorCode::AccountOwnedByWrongProgram.into());
|
|
|
|
}
|
|
|
|
|
|
|
|
let data = self.try_borrow_data()?;
|
|
|
|
|
|
|
|
Ok(Ref::map(data, |data| {
|
|
|
|
bytemuck::from_bytes(&data[8..mem::size_of::<T>() + 8])
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
}
|