use crate::account_view::AccountView;
use crate::address::Address;
use crate::borrow::Ref;
use crate::error::ProgramError;
use crate::project::Projectable;
#[inline]
pub fn read_field<'a, T: Projectable>(
account: &'a AccountView<'a>,
offset: usize,
) -> Result<Ref<'a, T>, ProgramError> {
crate::project::project::<T>(account, offset, None)
}
#[inline]
pub fn read_field_pod<'a, T: crate::Pod>(
account: &'a AccountView<'a>,
offset: usize,
) -> Result<Ref<'a, 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) };
let state_ptr = account.acquire_shared()?;
Ok(Ref::new(unsafe { &*(ptr as *const T) }, state_ptr))
}
#[inline]
pub fn read_address<'a>(
account: &'a AccountView<'a>,
offset: usize,
) -> Result<Ref<'a, Address>, ProgramError> {
let data_len = account.data_len();
if offset.checked_add(32).is_none_or(|end| end > data_len) {
return Err(ProgramError::AccountDataTooSmall);
}
let ptr = unsafe { account.data_ptr_unchecked().add(offset) };
let state_ptr = account.acquire_shared()?;
Ok(Ref::new(unsafe { &*(ptr as *const Address) }, state_ptr))
}
#[inline]
pub fn read_le_u64(account: &AccountView<'_>, offset: usize) -> Result<u64, ProgramError> {
let data_len = account.data_len();
if offset.checked_add(8).is_none_or(|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).is_none_or(|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).is_none_or(|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<'a>(
account: &'a AccountView<'a>,
offset: usize,
len: usize,
) -> Result<Ref<'a, [u8]>, ProgramError> {
let data_len = account.data_len();
if offset.checked_add(len).is_none_or(|end| end > data_len) {
return Err(ProgramError::AccountDataTooSmall);
}
let ptr = unsafe { account.data_ptr_unchecked().add(offset) };
let state_ptr = account.acquire_shared()?;
Ok(Ref::new(
unsafe { core::slice::from_raw_parts(ptr, len) },
state_ptr,
))
}
#[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)
}