pub mod account_state;
pub mod entry;
pub mod whitelist;
use {
bytemuck::{Pod, Zeroable},
core::mem,
pinocchio::program_error::ProgramError,
};
pub trait SizeOf {
const SIZE_OF: usize;
}
impl<T: Pod> SizeOf for T {
const SIZE_OF: usize = mem::size_of::<T>();
}
pub type COption<T> = ([u8; 4], T);
#[repr(C, packed)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
pub struct PodCOption<T>
where
T: Pod + Default,
{
pub(crate) option: [u8; 4],
pub(crate) value: T,
}
impl<T> PodCOption<T>
where
T: Pod + Default,
{
pub const NONE: [u8; 4] = [0; 4];
pub const SOME: [u8; 4] = [1, 0, 0, 0];
pub fn none() -> Self {
Self {
option: Self::NONE,
value: T::default(),
}
}
pub const fn some(value: T) -> Self {
Self {
option: Self::SOME,
value,
}
}
pub fn unwrap_or(self, default: T) -> T {
if self.option == Self::NONE {
default
} else {
self.value
}
}
pub fn is_some(&self) -> bool {
self.option == Self::SOME
}
pub fn is_none(&self) -> bool {
self.option == Self::NONE
}
pub fn ok_or<E>(self, error: E) -> Result<T, E> {
match self {
Self {
option: Self::SOME,
value,
} => Ok(value),
_ => Err(error),
}
}
}
impl<T: Pod + Default> From<COption<T>> for PodCOption<T> {
fn from(opt: COption<T>) -> Self {
if opt.0[0] == 0 {
Self {
option: Self::NONE,
value: T::default(),
}
} else {
Self {
option: Self::SOME,
value: opt.1,
}
}
}
}
pub trait Initializable {
fn is_initialized(&self) -> bool;
}
#[inline(always)]
pub fn load<'data, T: Pod + Initializable>(input: &'data [u8]) -> Result<&'data T, ProgramError> {
if input.len() != T::SIZE_OF {
return Err(ProgramError::InvalidAccountData);
}
let account = bytemuck::from_bytes::<T>(input);
if !account.is_initialized() {
return Err(ProgramError::UninitializedAccount);
}
Ok(account)
}
#[inline(always)]
pub fn load_mut<'data, T: Pod + Initializable>(
input: &'data mut [u8],
) -> Result<&'data mut T, ProgramError> {
if input.len() != T::SIZE_OF {
return Err(ProgramError::InvalidAccountData);
}
let account = bytemuck::from_bytes_mut::<T>(input);
if !account.is_initialized() {
return Err(ProgramError::UninitializedAccount);
}
Ok(account)
}
#[inline(always)]
pub fn load_unchecked<'data, T: Pod>(input: &'data [u8]) -> Result<&'data T, ProgramError> {
if input.len() != T::SIZE_OF {
return Err(ProgramError::InvalidAccountData);
}
Ok(bytemuck::from_bytes::<T>(input))
}
#[inline(always)]
pub fn load_mut_unchecked<'data, T: Pod>(
input: &'data mut [u8],
) -> Result<&'data mut T, ProgramError> {
if input.len() != T::SIZE_OF {
return Err(ProgramError::InvalidAccountData);
}
Ok(bytemuck::from_bytes_mut::<T>(input))
}