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 body(&self) -> SliceCursor<'a> {
74 SliceCursor::new(&self.data[HEADER_LEN..])
75 }
76
77 #[inline(always)]
79 pub fn body_bytes(&self) -> &'a [u8] {
80 &self.data[HEADER_LEN..]
81 }
82
83 #[inline(always)]
85 pub fn raw(&self) -> &'a [u8] {
86 self.data
87 }
88
89 #[inline(always)]
91 pub fn u64_at(&self, offset: usize) -> Result<u64, ProgramError> {
92 if offset + 8 > self.data.len() {
93 return Err(ProgramError::InvalidAccountData);
94 }
95 Ok(u64::from_le_bytes([
96 self.data[offset],
97 self.data[offset + 1],
98 self.data[offset + 2],
99 self.data[offset + 3],
100 self.data[offset + 4],
101 self.data[offset + 5],
102 self.data[offset + 6],
103 self.data[offset + 7],
104 ]))
105 }
106
107 #[inline(always)]
109 pub fn address_at(&self, offset: usize) -> Result<&'a [u8; 32], ProgramError> {
110 if offset + 32 > self.data.len() {
111 return Err(ProgramError::InvalidAccountData);
112 }
113 Ok(unsafe { &*(self.data.as_ptr().add(offset) as *const [u8; 32]) })
115 }
116
117 #[inline(always)]
119 pub fn overlay_at<T: super::Pod + super::FixedLayout>(
120 &self,
121 offset: usize,
122 ) -> Result<&'a T, ProgramError> {
123 if offset > self.data.len() {
124 return Err(ProgramError::InvalidAccountData);
125 }
126 pod_from_bytes::<T>(&self.data[offset..])
127 }
128}