use super::cursor::SliceCursor;
use super::header::{AccountHeader, HEADER_LEN};
use super::pod::pod_from_bytes;
use hopper_runtime::error::ProgramError;
pub struct AccountReader<'a> {
data: &'a [u8],
}
impl<'a> AccountReader<'a> {
#[inline(always)]
pub fn new(data: &'a [u8]) -> Result<Self, ProgramError> {
if data.len() < HEADER_LEN {
return Err(ProgramError::AccountDataTooSmall);
}
Ok(Self { data })
}
#[inline(always)]
pub fn new_checked(
data: &'a [u8],
disc: u8,
min_version: u8,
layout_id: &[u8; 8],
) -> Result<Self, ProgramError> {
super::header::check_header(data, disc, min_version, layout_id)?;
Ok(Self { data })
}
#[inline(always)]
pub fn header(&self) -> &AccountHeader {
unsafe { &*(self.data.as_ptr() as *const AccountHeader) }
}
#[inline(always)]
pub fn discriminator(&self) -> u8 {
self.data[0]
}
#[inline(always)]
pub fn version(&self) -> u8 {
self.data[1]
}
#[inline(always)]
pub fn flags(&self) -> u16 {
u16::from_le_bytes([self.data[2], self.data[3]])
}
#[inline(always)]
pub fn layout_id(&self) -> [u8; 8] {
let mut id = [0u8; 8];
id.copy_from_slice(&self.data[4..12]);
id
}
#[inline(always)]
pub fn body(&self) -> SliceCursor<'a> {
SliceCursor::new(&self.data[HEADER_LEN..])
}
#[inline(always)]
pub fn body_bytes(&self) -> &'a [u8] {
&self.data[HEADER_LEN..]
}
#[inline(always)]
pub fn raw(&self) -> &'a [u8] {
self.data
}
#[inline(always)]
pub fn u64_at(&self, offset: usize) -> Result<u64, ProgramError> {
if offset + 8 > self.data.len() {
return Err(ProgramError::InvalidAccountData);
}
Ok(u64::from_le_bytes([
self.data[offset],
self.data[offset + 1],
self.data[offset + 2],
self.data[offset + 3],
self.data[offset + 4],
self.data[offset + 5],
self.data[offset + 6],
self.data[offset + 7],
]))
}
#[inline(always)]
pub fn address_at(&self, offset: usize) -> Result<&'a [u8; 32], ProgramError> {
if offset + 32 > self.data.len() {
return Err(ProgramError::InvalidAccountData);
}
Ok(unsafe { &*(self.data.as_ptr().add(offset) as *const [u8; 32]) })
}
#[inline(always)]
pub fn overlay_at<T: super::Pod + super::FixedLayout>(
&self,
offset: usize,
) -> Result<&'a T, ProgramError> {
if offset > self.data.len() {
return Err(ProgramError::InvalidAccountData);
}
pod_from_bytes::<T>(&self.data[offset..])
}
}