1#![no_std]
5
6use hayabusa_errors::{ErrorCode, Result};
7use hayabusa_utility::fail_with_ctx;
8use pinocchio::account_info::AccountInfo;
9
10pub trait FromAccountInfos<'a>
11where
12 Self: Sized,
13{
14 fn try_from_account_infos(account_infos: &mut AccountIter<'a>) -> Result<Self>;
15}
16
17pub struct Ctx<'a, T>
22where
23 T: FromAccountInfos<'a>,
24{
25 pub accounts: T,
26 pub remaining_accounts: AccountIter<'a>,
27}
28
29impl<'a, T> Ctx<'a, T>
30where
31 T: FromAccountInfos<'a>,
32{
33 #[inline(always)]
34 pub fn construct(account_infos: &'a [AccountInfo]) -> Result<Self> {
35 let mut iter = AccountIter::new(account_infos);
36
37 let accounts = T::try_from_account_infos(&mut iter)?;
38
39 Ok(Ctx {
40 accounts,
41 remaining_accounts: iter,
42 })
43 }
44}
45
46impl<'a, T> core::ops::Deref for Ctx<'a, T>
47where
48 T: FromAccountInfos<'a>,
49{
50 type Target = T;
51
52 #[inline(always)]
53 fn deref(&self) -> &Self::Target {
54 &self.accounts
55 }
56}
57
58#[derive(Clone)]
59pub struct AccountIter<'a> {
60 slice: &'a [AccountInfo],
61 index: usize,
62}
63
64impl<'a> AccountIter<'a> {
65 #[inline(always)]
66 pub fn new(slice: &'a [AccountInfo]) -> Self {
67 Self { slice, index: 0 }
68 }
69
70 #[allow(clippy::should_implement_trait)]
71 #[inline(always)]
72 pub fn next(&mut self) -> Result<&'a AccountInfo> {
73 if self.index >= self.slice.len() {
74 fail_with_ctx!(
75 "HAYABUSA_ACCOUNT_ITER_NEXT_NOT_PRESENT",
76 ErrorCode::InvalidAccount,
77 );
78 }
79
80 let account_info = &self.slice[self.index];
81 self.index += 1;
82
83 Ok(account_info)
84 }
85}