use crate::account_view::AccountView;
use crate::address::Address;
use crate::error::ProgramError;
use crate::project::Projectable;
#[inline]
pub fn read_field<T: Projectable>(
account: &AccountView,
offset: usize,
) -> Result<&T, ProgramError> {
crate::project::project::<T>(account, offset, None)
}
#[inline]
pub fn read_field_pod<T: crate::Pod>(
account: &AccountView,
offset: usize,
) -> Result<&T, ProgramError> {
let data_len = account.data_len();
let size = core::mem::size_of::<T>();
let end = offset
.checked_add(size)
.ok_or(ProgramError::ArithmeticOverflow)?;
if end > data_len {
return Err(ProgramError::AccountDataTooSmall);
}
let ptr = unsafe { account.data_ptr_unchecked().add(offset) };
Ok(unsafe { &*(ptr as *const T) })
}
#[inline]
pub fn read_address(account: &AccountView, offset: usize) -> Result<&Address, ProgramError> {
let data_len = account.data_len();
if offset.checked_add(32).map_or(true, |end| end > data_len) {
return Err(ProgramError::AccountDataTooSmall);
}
let ptr = unsafe { account.data_ptr_unchecked().add(offset) };
Ok(unsafe { &*(ptr as *const Address) })
}
#[inline]
pub fn read_le_u64(account: &AccountView, offset: usize) -> Result<u64, ProgramError> {
let data_len = account.data_len();
if offset.checked_add(8).map_or(true, |end| end > data_len) {
return Err(ProgramError::AccountDataTooSmall);
}
let ptr = unsafe { account.data_ptr_unchecked().add(offset) };
let mut bytes = [0u8; 8];
unsafe {
core::ptr::copy_nonoverlapping(ptr, bytes.as_mut_ptr(), 8);
}
Ok(u64::from_le_bytes(bytes))
}
#[inline]
pub fn read_le_u32(account: &AccountView, offset: usize) -> Result<u32, ProgramError> {
let data_len = account.data_len();
if offset.checked_add(4).map_or(true, |end| end > data_len) {
return Err(ProgramError::AccountDataTooSmall);
}
let ptr = unsafe { account.data_ptr_unchecked().add(offset) };
let mut bytes = [0u8; 4];
unsafe {
core::ptr::copy_nonoverlapping(ptr, bytes.as_mut_ptr(), 4);
}
Ok(u32::from_le_bytes(bytes))
}
#[inline]
pub fn read_le_u16(account: &AccountView, offset: usize) -> Result<u16, ProgramError> {
let data_len = account.data_len();
if offset.checked_add(2).map_or(true, |end| end > data_len) {
return Err(ProgramError::AccountDataTooSmall);
}
let ptr = unsafe { account.data_ptr_unchecked().add(offset) };
let mut bytes = [0u8; 2];
unsafe {
core::ptr::copy_nonoverlapping(ptr, bytes.as_mut_ptr(), 2);
}
Ok(u16::from_le_bytes(bytes))
}
#[inline]
pub fn read_u8(account: &AccountView, offset: usize) -> Result<u8, ProgramError> {
if offset >= account.data_len() {
return Err(ProgramError::AccountDataTooSmall);
}
Ok(unsafe { *account.data_ptr_unchecked().add(offset) })
}
#[inline]
pub fn read_bool(account: &AccountView, offset: usize) -> Result<bool, ProgramError> {
read_u8(account, offset).map(|b| b != 0)
}
#[inline]
pub fn read_bytes(account: &AccountView, offset: usize, len: usize) -> Result<&[u8], ProgramError> {
let data_len = account.data_len();
if offset.checked_add(len).map_or(true, |end| end > data_len) {
return Err(ProgramError::AccountDataTooSmall);
}
let ptr = unsafe { account.data_ptr_unchecked().add(offset) };
Ok(unsafe { core::slice::from_raw_parts(ptr, len) })
}
#[inline]
pub fn field_eq(
account: &AccountView,
offset: usize,
expected: &[u8],
) -> Result<bool, ProgramError> {
let actual = read_bytes(account, offset, expected.len())?;
Ok(actual == expected)
}