1use hopper_runtime::{error::ProgramError, AccountView, Address, ProgramResult, Ref, RefMut};
24
25pub struct Unresolved;
29pub struct Resolved;
31pub struct Validated;
33pub struct Executed;
35
36pub struct PhasedFrame<'a, P> {
44 program_id: &'a Address,
45 accounts: &'a [AccountView],
46 ix_data: &'a [u8],
47 mutable_borrows: u64,
48 _phase: core::marker::PhantomData<P>,
49}
50
51impl<'a> PhasedFrame<'a, Unresolved> {
52 #[inline(always)]
54 pub fn new(
55 program_id: &'a Address,
56 accounts: &'a [AccountView],
57 ix_data: &'a [u8],
58 ) -> Result<Self, ProgramError> {
59 if accounts.len() > crate::frame::MAX_FRAME_ACCOUNTS {
60 return Err(ProgramError::InvalidArgument);
61 }
62 Ok(Self {
63 program_id,
64 accounts,
65 ix_data,
66 mutable_borrows: 0,
67 _phase: core::marker::PhantomData,
68 })
69 }
70
71 #[inline]
85 pub fn resolve<T, F>(
86 self,
87 min_accounts: usize,
88 f: F,
89 ) -> Result<ResolvedFrame<'a, T>, ProgramError>
90 where
91 F: FnOnce(&'a [AccountView], &'a Address) -> Result<T, ProgramError>,
92 {
93 if self.accounts.len() < min_accounts {
94 return Err(ProgramError::NotEnoughAccountKeys);
95 }
96 let resolved = f(self.accounts, self.program_id)?;
97 Ok(ResolvedFrame {
98 program_id: self.program_id,
99 accounts: self.accounts,
100 ix_data: self.ix_data,
101 mutable_borrows: self.mutable_borrows,
102 resolved,
103 })
104 }
105}
106
107pub struct ResolvedFrame<'a, T> {
111 pub(crate) program_id: &'a Address,
112 pub(crate) accounts: &'a [AccountView],
113 pub(crate) ix_data: &'a [u8],
114 pub(crate) mutable_borrows: u64,
115 pub(crate) resolved: T,
116}
117
118impl<'a, T> ResolvedFrame<'a, T> {
119 #[inline(always)]
121 pub fn program_id(&self) -> &Address {
122 self.program_id
123 }
124
125 #[inline(always)]
127 pub fn ix_data(&self) -> &[u8] {
128 self.ix_data
129 }
130
131 #[inline(always)]
133 pub fn accounts(&self) -> &T {
134 &self.resolved
135 }
136
137 #[inline]
150 pub fn validate<F>(self, f: F) -> Result<ValidatedFrame<'a, T>, ProgramError>
151 where
152 F: FnOnce(&T, &Address) -> ProgramResult,
153 {
154 f(&self.resolved, self.program_id)?;
155 Ok(ValidatedFrame {
156 program_id: self.program_id,
157 accounts: self.accounts,
158 ix_data: self.ix_data,
159 mutable_borrows: self.mutable_borrows,
160 resolved: self.resolved,
161 })
162 }
163}
164
165pub struct ValidatedFrame<'a, T> {
167 pub(crate) program_id: &'a Address,
168 pub(crate) accounts: &'a [AccountView],
169 pub(crate) ix_data: &'a [u8],
170 pub(crate) mutable_borrows: u64,
171 pub(crate) resolved: T,
172}
173
174impl<'a, T> ValidatedFrame<'a, T> {
175 #[inline(always)]
177 pub fn program_id(&self) -> &Address {
178 self.program_id
179 }
180
181 #[inline(always)]
183 pub fn ix_data(&self) -> &[u8] {
184 self.ix_data
185 }
186
187 #[inline(always)]
189 pub fn accounts(&self) -> &T {
190 &self.resolved
191 }
192
193 #[inline]
206 pub fn execute<R, F>(mut self, f: F) -> Result<R, ProgramError>
207 where
208 F: FnOnce(&mut ExecutionContext<'a, '_, T>) -> Result<R, ProgramError>,
209 {
210 let mut ctx = ExecutionContext {
211 program_id: self.program_id,
212 accounts: self.accounts,
213 ix_data: self.ix_data,
214 mutable_borrows: &mut self.mutable_borrows,
215 resolved: &self.resolved,
216 };
217 f(&mut ctx)
218 }
219}
220
221pub struct ExecutionContext<'a, 'f, T> {
223 pub(crate) program_id: &'a Address,
224 pub(crate) accounts: &'a [AccountView],
225 pub(crate) ix_data: &'a [u8],
226 pub(crate) mutable_borrows: &'f mut u64,
227 pub(crate) resolved: &'f T,
228}
229
230impl<'a, 'f, T> ExecutionContext<'a, 'f, T> {
231 #[inline(always)]
233 pub fn program_id(&self) -> &'a Address {
234 self.program_id
235 }
236
237 #[inline(always)]
239 pub fn ix_data(&self) -> &'a [u8] {
240 self.ix_data
241 }
242
243 #[inline(always)]
245 pub fn resolved(&self) -> &T {
246 self.resolved
247 }
248
249 #[inline]
251 pub fn borrow_mut(&mut self, index: usize) -> Result<RefMut<'a, [u8]>, ProgramError> {
252 if index >= self.accounts.len() {
253 return Err(ProgramError::NotEnoughAccountKeys);
254 }
255 let bit = 1u64 << (index as u32);
256 if *self.mutable_borrows & bit != 0 {
257 return Err(ProgramError::AccountBorrowFailed);
258 }
259 *self.mutable_borrows |= bit;
260 match self.accounts[index].try_borrow_mut() {
262 Ok(data) => Ok(data),
263 Err(error) => {
264 *self.mutable_borrows &= !bit;
265 Err(error)
266 }
267 }
268 }
269
270 #[inline(always)]
272 pub fn borrow(&self, index: usize) -> Result<Ref<'a, [u8]>, ProgramError> {
273 if index >= self.accounts.len() {
274 return Err(ProgramError::NotEnoughAccountKeys);
275 }
276 self.accounts[index].try_borrow()
278 }
279
280 #[inline(always)]
282 pub fn account(&self, index: usize) -> Result<&'a AccountView, ProgramError> {
283 self.accounts
284 .get(index)
285 .ok_or(ProgramError::NotEnoughAccountKeys)
286 }
287}