hopper_core/account/
reader.rs1use super::cursor::SliceCursor;
4use super::header::{AccountHeader, HEADER_LEN};
5use super::pod::pod_from_bytes;
6use hopper_runtime::error::ProgramError;
7
8pub struct AccountReader<'a> {
12 data: &'a [u8],
13}
14
15impl<'a> AccountReader<'a> {
16 #[inline(always)]
18 pub fn new(data: &'a [u8]) -> Result<Self, ProgramError> {
19 if data.len() < HEADER_LEN {
20 return Err(ProgramError::AccountDataTooSmall);
21 }
22 Ok(Self { data })
23 }
24
25 #[inline(always)]
27 pub fn new_checked(
28 data: &'a [u8],
29 disc: u8,
30 min_version: u8,
31 layout_id: &[u8; 8],
32 ) -> Result<Self, ProgramError> {
33 super::header::check_header(data, disc, min_version, layout_id)?;
34 Ok(Self { data })
35 }
36
37 #[inline(always)]
39 pub fn header(&self) -> &AccountHeader {
40 unsafe { &*(self.data.as_ptr() as *const AccountHeader) }
43 }
44
45 #[inline(always)]
47 pub fn discriminator(&self) -> u8 {
48 self.data[0]
49 }
50
51 #[inline(always)]
53 pub fn version(&self) -> u8 {
54 self.data[1]
55 }
56
57 #[inline(always)]
59 pub fn flags(&self) -> u16 {
60 u16::from_le_bytes([self.data[2], self.data[3]])
61 }
62
63 #[inline(always)]
65 pub fn layout_id(&self) -> [u8; 8] {
66 let mut id = [0u8; 8];
67 id.copy_from_slice(&self.data[4..12]);
68 id
69 }
70
71 #[inline(always)]
73 pub fn schema_epoch(&self) -> u32 {
74 u32::from_le_bytes([self.data[12], self.data[13], self.data[14], self.data[15]])
75 }
76
77 #[inline(always)]
79 pub fn body(&self) -> SliceCursor<'a> {
80 SliceCursor::new(&self.data[HEADER_LEN..])
81 }
82
83 #[inline(always)]
85 pub fn body_bytes(&self) -> &'a [u8] {
86 &self.data[HEADER_LEN..]
87 }
88
89 #[inline(always)]
91 pub fn raw(&self) -> &'a [u8] {
92 self.data
93 }
94
95 #[inline(always)]
97 pub fn u64_at(&self, offset: usize) -> Result<u64, ProgramError> {
98 if offset + 8 > self.data.len() {
99 return Err(ProgramError::InvalidAccountData);
100 }
101 Ok(u64::from_le_bytes([
102 self.data[offset],
103 self.data[offset + 1],
104 self.data[offset + 2],
105 self.data[offset + 3],
106 self.data[offset + 4],
107 self.data[offset + 5],
108 self.data[offset + 6],
109 self.data[offset + 7],
110 ]))
111 }
112
113 #[inline(always)]
115 pub fn address_at(&self, offset: usize) -> Result<&'a [u8; 32], ProgramError> {
116 if offset + 32 > self.data.len() {
117 return Err(ProgramError::InvalidAccountData);
118 }
119 Ok(unsafe { &*(self.data.as_ptr().add(offset) as *const [u8; 32]) })
121 }
122
123 #[inline(always)]
125 pub fn overlay_at<T: super::Pod + super::FixedLayout>(
126 &self,
127 offset: usize,
128 ) -> Result<&'a T, ProgramError> {
129 if offset > self.data.len() {
130 return Err(ProgramError::InvalidAccountData);
131 }
132 pod_from_bytes::<T>(&self.data[offset..])
133 }
134}