jiminy_core/account/
reader.rs1use pinocchio::error::ProgramError;
4
5use super::cursor::SliceCursor;
6use super::header::{AccountHeader, HEADER_LEN};
7
8pub struct AccountReader<'a> {
13 data: &'a [u8],
14 body_offset: usize,
15}
16
17impl<'a> AccountReader<'a> {
18 #[inline(always)]
20 pub fn new(data: &'a [u8]) -> Result<Self, ProgramError> {
21 if data.len() < HEADER_LEN {
22 return Err(ProgramError::AccountDataTooSmall);
23 }
24 Ok(Self {
25 data,
26 body_offset: HEADER_LEN,
27 })
28 }
29
30 #[inline(always)]
32 pub fn new_checked(
33 data: &'a [u8],
34 expected_disc: u8,
35 min_version: u8,
36 layout_id: &[u8; 8],
37 ) -> Result<Self, ProgramError> {
38 if data.len() < HEADER_LEN {
39 return Err(ProgramError::AccountDataTooSmall);
40 }
41 if data[0] != expected_disc {
42 return Err(ProgramError::InvalidAccountData);
43 }
44 if data[1] < min_version {
45 return Err(ProgramError::InvalidAccountData);
46 }
47 if data[4..12] != *layout_id {
48 return Err(ProgramError::InvalidAccountData);
49 }
50 Ok(Self {
51 data,
52 body_offset: HEADER_LEN,
53 })
54 }
55
56 #[inline(always)]
58 pub fn header(&self) -> &AccountHeader {
59 unsafe { &*(self.data.as_ptr() as *const AccountHeader) }
61 }
62
63 #[inline(always)]
65 pub fn discriminator(&self) -> u8 {
66 self.data[0]
67 }
68
69 #[inline(always)]
71 pub fn version(&self) -> u8 {
72 self.data[1]
73 }
74
75 #[inline(always)]
77 pub fn flags(&self) -> u16 {
78 u16::from_le_bytes([self.data[2], self.data[3]])
79 }
80
81 #[inline(always)]
83 pub fn layout_id(&self) -> [u8; 8] {
84 let mut id = [0u8; 8];
85 id.copy_from_slice(&self.data[4..12]);
86 id
87 }
88
89 #[inline(always)]
91 pub fn body(&self) -> SliceCursor<'a> {
92 SliceCursor::new(&self.data[self.body_offset..])
93 }
94
95 #[inline(always)]
97 pub fn body_bytes(&self) -> &'a [u8] {
98 &self.data[self.body_offset..]
99 }
100
101 #[inline(always)]
103 pub fn raw(&self) -> &'a [u8] {
104 self.data
105 }
106
107 #[inline(always)]
109 pub fn pubkey_at(&self, offset: usize) -> Result<&'a [u8; 32], ProgramError> {
110 let abs = self.body_offset + offset;
111 if abs + 32 > self.data.len() {
112 return Err(ProgramError::AccountDataTooSmall);
113 }
114 Ok(unsafe { &*(self.data.as_ptr().add(abs) as *const [u8; 32]) })
116 }
117
118 #[inline(always)]
120 pub fn u64_at(&self, offset: usize) -> Result<u64, ProgramError> {
121 let abs = self.body_offset + offset;
122 if abs + 8 > self.data.len() {
123 return Err(ProgramError::AccountDataTooSmall);
124 }
125 Ok(u64::from_le_bytes([
126 self.data[abs],
127 self.data[abs + 1],
128 self.data[abs + 2],
129 self.data[abs + 3],
130 self.data[abs + 4],
131 self.data[abs + 5],
132 self.data[abs + 6],
133 self.data[abs + 7],
134 ]))
135 }
136
137 #[inline(always)]
139 pub fn u32_at(&self, offset: usize) -> Result<u32, ProgramError> {
140 let abs = self.body_offset + offset;
141 if abs + 4 > self.data.len() {
142 return Err(ProgramError::AccountDataTooSmall);
143 }
144 Ok(u32::from_le_bytes([
145 self.data[abs],
146 self.data[abs + 1],
147 self.data[abs + 2],
148 self.data[abs + 3],
149 ]))
150 }
151
152 #[inline(always)]
154 pub fn u16_at(&self, offset: usize) -> Result<u16, ProgramError> {
155 let abs = self.body_offset + offset;
156 if abs + 2 > self.data.len() {
157 return Err(ProgramError::AccountDataTooSmall);
158 }
159 Ok(u16::from_le_bytes([self.data[abs], self.data[abs + 1]]))
160 }
161
162 #[inline(always)]
164 pub fn u8_at(&self, offset: usize) -> Result<u8, ProgramError> {
165 let abs = self.body_offset + offset;
166 if abs >= self.data.len() {
167 return Err(ProgramError::AccountDataTooSmall);
168 }
169 Ok(self.data[abs])
170 }
171
172 #[inline(always)]
174 pub fn i64_at(&self, offset: usize) -> Result<i64, ProgramError> {
175 let abs = self.body_offset + offset;
176 if abs + 8 > self.data.len() {
177 return Err(ProgramError::AccountDataTooSmall);
178 }
179 Ok(i64::from_le_bytes([
180 self.data[abs],
181 self.data[abs + 1],
182 self.data[abs + 2],
183 self.data[abs + 3],
184 self.data[abs + 4],
185 self.data[abs + 5],
186 self.data[abs + 6],
187 self.data[abs + 7],
188 ]))
189 }
190
191 #[inline(always)]
193 pub fn bool_at(&self, offset: usize) -> Result<bool, ProgramError> {
194 Ok(self.u8_at(offset)? != 0)
195 }
196
197 #[inline(always)]
199 pub fn bytes_at<const N: usize>(&self, offset: usize) -> Result<[u8; N], ProgramError> {
200 let abs = self.body_offset + offset;
201 if abs + N > self.data.len() {
202 return Err(ProgramError::AccountDataTooSmall);
203 }
204 let mut out = [0u8; N];
205 out.copy_from_slice(&self.data[abs..abs + N]);
206 Ok(out)
207 }
208
209 #[inline(always)]
211 pub fn body_len(&self) -> usize {
212 self.data.len().saturating_sub(self.body_offset)
213 }
214}