jiminy_core/account/
cursor.rs1use pinocchio::{error::ProgramError, Address};
11
12macro_rules! impl_cursor_read {
16 ($( $name:ident -> $ty:ty, $size:literal; )*) => {
17 $(
18 #[inline(always)]
19 pub fn $name(&mut self) -> Result<$ty, ProgramError> {
20 let end = self.pos + $size;
21 if end > self.data.len() {
22 return Err(ProgramError::AccountDataTooSmall);
23 }
24 let val = <$ty>::from_le_bytes(self.data[self.pos..end].try_into().unwrap());
25 self.pos = end;
26 Ok(val)
27 }
28 )*
29 };
30}
31
32macro_rules! impl_cursor_write {
34 ($( $name:ident ($ty:ty), $size:literal; )*) => {
35 $(
36 #[inline(always)]
37 pub fn $name(&mut self, val: $ty) -> Result<(), ProgramError> {
38 let end = self.pos + $size;
39 if end > self.data.len() {
40 return Err(ProgramError::AccountDataTooSmall);
41 }
42 self.data[self.pos..end].copy_from_slice(&val.to_le_bytes());
43 self.pos = end;
44 Ok(())
45 }
46 )*
47 };
48}
49
50pub struct SliceCursor<'a> {
65 data: &'a [u8],
66 pos: usize,
67}
68
69impl<'a> SliceCursor<'a> {
70 #[inline(always)]
71 pub fn new(data: &'a [u8]) -> Self {
72 Self { data, pos: 0 }
73 }
74
75 #[inline(always)]
77 pub fn remaining(&self) -> usize {
78 self.data.len().saturating_sub(self.pos)
79 }
80
81 #[inline(always)]
83 pub fn position(&self) -> usize {
84 self.pos
85 }
86
87 #[inline(always)]
88 pub fn read_u8(&mut self) -> Result<u8, ProgramError> {
89 if self.pos >= self.data.len() {
90 return Err(ProgramError::AccountDataTooSmall);
91 }
92 let val = self.data[self.pos];
93 self.pos += 1;
94 Ok(val)
95 }
96
97 impl_cursor_read! {
99 read_u16 -> u16, 2;
100 read_u32 -> u32, 4;
101 read_u64 -> u64, 8;
102 read_u128 -> u128, 16;
103 read_i16 -> i16, 2;
104 read_i32 -> i32, 4;
105 read_i64 -> i64, 8;
106 read_i128 -> i128, 16;
107 }
108
109 #[inline(always)]
111 pub fn read_bool(&mut self) -> Result<bool, ProgramError> {
112 Ok(self.read_u8()? != 0)
113 }
114
115 #[inline(always)]
116 pub fn read_i8(&mut self) -> Result<i8, ProgramError> {
117 Ok(self.read_u8()? as i8)
118 }
119
120 #[inline(always)]
121 pub fn read_address(&mut self) -> Result<Address, ProgramError> {
122 let end = self.pos + 32;
123 if end > self.data.len() {
124 return Err(ProgramError::AccountDataTooSmall);
125 }
126 let arr: [u8; 32] = self.data[self.pos..end].try_into().unwrap();
127 self.pos = end;
128 Ok(arr.into())
129 }
130
131 #[inline(always)]
133 pub fn skip(&mut self, n: usize) -> Result<(), ProgramError> {
134 let end = self.pos.checked_add(n).ok_or(ProgramError::AccountDataTooSmall)?;
135 if end > self.data.len() {
136 return Err(ProgramError::AccountDataTooSmall);
137 }
138 self.pos = end;
139 Ok(())
140 }
141
142 #[inline(always)]
144 pub fn data_from_position(&self) -> &'a [u8] {
145 if self.pos >= self.data.len() {
146 &[]
147 } else {
148 &self.data[self.pos..]
149 }
150 }
151
152 #[inline(always)]
154 pub fn from_instruction(data: &'a [u8], min_len: usize) -> Result<Self, ProgramError> {
155 if data.len() < min_len {
156 return Err(ProgramError::InvalidInstructionData);
157 }
158 Ok(Self { data, pos: 0 })
159 }
160}
161
162pub struct DataWriter<'a> {
177 data: &'a mut [u8],
178 pos: usize,
179}
180
181impl<'a> DataWriter<'a> {
182 #[inline(always)]
183 pub fn new(data: &'a mut [u8]) -> Self {
184 Self { data, pos: 0 }
185 }
186
187 #[inline(always)]
189 pub fn written(&self) -> usize {
190 self.pos
191 }
192
193 #[inline(always)]
194 pub fn write_u8(&mut self, val: u8) -> Result<(), ProgramError> {
195 if self.pos >= self.data.len() {
196 return Err(ProgramError::AccountDataTooSmall);
197 }
198 self.data[self.pos] = val;
199 self.pos += 1;
200 Ok(())
201 }
202
203 impl_cursor_write! {
205 write_u16(u16), 2;
206 write_u32(u32), 4;
207 write_u64(u64), 8;
208 write_u128(u128), 16;
209 write_i16(i16), 2;
210 write_i32(i32), 4;
211 write_i64(i64), 8;
212 write_i128(i128), 16;
213 }
214
215 #[inline(always)]
217 pub fn write_bool(&mut self, val: bool) -> Result<(), ProgramError> {
218 self.write_u8(val as u8)
219 }
220
221 #[inline(always)]
222 pub fn write_i8(&mut self, val: i8) -> Result<(), ProgramError> {
223 self.write_u8(val as u8)
224 }
225
226 #[inline(always)]
227 pub fn write_address(&mut self, addr: &Address) -> Result<(), ProgramError> {
228 let end = self.pos + 32;
229 if end > self.data.len() {
230 return Err(ProgramError::AccountDataTooSmall);
231 }
232 self.data[self.pos..end].copy_from_slice(addr.as_array());
233 self.pos = end;
234 Ok(())
235 }
236}
237
238#[inline(always)]
245pub fn zero_init(data: &mut [u8]) {
246 data.fill(0);
247}
248
249#[inline(always)]
251pub fn write_discriminator(data: &mut [u8], discriminator: u8) -> Result<(), ProgramError> {
252 if data.is_empty() {
253 return Err(ProgramError::AccountDataTooSmall);
254 }
255 data[0] = discriminator;
256 Ok(())
257}