Skip to content

Commit 23d48a3

Browse files
committed
all three impls
1 parent 566d41a commit 23d48a3

File tree

4 files changed

+301
-122
lines changed

4 files changed

+301
-122
lines changed

programs/system/src/callback.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
use pinocchio::{
2+
account_info::AccountInfo,
3+
cpi,
4+
instruction::{AccountMeta, Instruction, Signer},
5+
pubkey::Pubkey,
6+
ProgramResult,
7+
};
8+
9+
mod sealed {
10+
pub trait Sealed {}
11+
impl<T> Sealed for T where T: super::CanInvoke {}
12+
}
13+
14+
pub trait CanInvoke {
15+
type Accounts;
16+
17+
fn invoke_via(
18+
&self,
19+
invoke: impl for<'a> FnOnce(
20+
/* program_id: */ &'a Pubkey,
21+
/* accounts: */ &'a Self::Accounts,
22+
/* account_metas: */ &'a [AccountMeta],
23+
/* data: */ &'a [u8],
24+
) -> ProgramResult,
25+
slice_invoke: impl for<'a> FnOnce(
26+
/* program_id: */ &'a Pubkey,
27+
/* accounts: */ &'a [&'a AccountInfo],
28+
/* account_metas: */ &'a [AccountMeta],
29+
/* data: */ &'a [u8],
30+
) -> ProgramResult,
31+
) -> ProgramResult;
32+
}
33+
34+
pub trait Invoke: sealed::Sealed {
35+
fn invoke(&self) -> ProgramResult;
36+
fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult;
37+
}
38+
39+
impl<'a, const ACCOUNTS_LEN: usize, T> Invoke for T
40+
where
41+
T: CanInvoke<Accounts = [&'a AccountInfo; ACCOUNTS_LEN]>,
42+
{
43+
fn invoke(&self) -> ProgramResult {
44+
self.invoke_via(
45+
|program_id, accounts, account_metas, data| {
46+
let instruction = Instruction {
47+
program_id,
48+
accounts: &account_metas,
49+
data,
50+
};
51+
cpi::invoke(&instruction, accounts)
52+
},
53+
|program_id, accounts, account_metas, data| {
54+
let instruction = Instruction {
55+
program_id,
56+
accounts: &account_metas,
57+
data,
58+
};
59+
cpi::slice_invoke(&instruction, accounts)
60+
},
61+
)
62+
}
63+
64+
fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
65+
self.invoke_via(
66+
|program_id, accounts, account_metas, data| {
67+
let instruction = Instruction {
68+
program_id,
69+
accounts: &account_metas,
70+
data,
71+
};
72+
cpi::invoke_signed(&instruction, accounts, signers)
73+
},
74+
|program_id, accounts, account_metas, data| {
75+
let instruction = Instruction {
76+
program_id,
77+
accounts: &account_metas,
78+
data,
79+
};
80+
cpi::slice_invoke_signed(&instruction, accounts, signers)
81+
},
82+
)
83+
}
84+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
use pinocchio::{
2+
account_info::AccountInfo,
3+
cpi,
4+
instruction::{AccountMeta, Instruction, Signer},
5+
pubkey::Pubkey,
6+
ProgramResult,
7+
};
8+
9+
type SliceInvokeParts<'a> = InvokeParts<&'a [&'a AccountInfo], &'a [AccountMeta<'a>], &'a [u8]>;
10+
type FixedInvokeParts<'a, const N: usize> =
11+
InvokeParts<&'a [&'a AccountInfo; N], &'a [AccountMeta<'a>], &'a [u8]>;
12+
13+
pub trait InvokePartsType: sealed::Sealed {}
14+
impl InvokePartsType for SliceInvokeParts<'_> {}
15+
impl<const N: usize> InvokePartsType for FixedInvokeParts<'_, N> {}
16+
17+
pub struct InvokeParts<Accounts, Metas, Data> {
18+
pub program_id: Pubkey,
19+
pub accounts: Accounts,
20+
pub account_metas: Metas,
21+
pub instruction_data: Data,
22+
}
23+
24+
pub trait IntoInvokeParts {
25+
type Output: InvokePartsType;
26+
fn into_invoke_parts(self) -> Self::Output;
27+
}
28+
29+
pub trait Invoke: sealed::Sealed {
30+
fn invoke(self) -> ProgramResult;
31+
fn invoke_signed(self, signers: &[Signer]) -> ProgramResult;
32+
}
33+
34+
impl Invoke for SliceInvokeParts<'_> {
35+
fn invoke(self) -> ProgramResult {
36+
self.invoke_signed(&[])
37+
}
38+
39+
fn invoke_signed(self, signers: &[Signer]) -> ProgramResult {
40+
cpi::slice_invoke_signed(
41+
&Instruction {
42+
program_id: &self.program_id,
43+
data: &self.instruction_data,
44+
accounts: &self.account_metas,
45+
},
46+
self.accounts,
47+
signers,
48+
)
49+
}
50+
}
51+
52+
impl<const N: usize> Invoke for FixedInvokeParts<'_, N> {
53+
fn invoke(self) -> ProgramResult {
54+
self.invoke_signed(&[])
55+
}
56+
57+
fn invoke_signed(self, signers: &[Signer]) -> ProgramResult {
58+
cpi::invoke_signed(
59+
&Instruction {
60+
program_id: &self.program_id,
61+
data: &self.instruction_data,
62+
accounts: &self.account_metas,
63+
},
64+
self.accounts,
65+
signers,
66+
)
67+
}
68+
}
69+
70+
impl<T> Invoke for T
71+
where
72+
T: IntoInvokeParts,
73+
T::Output: Invoke,
74+
{
75+
fn invoke(self) -> ProgramResult {
76+
self.into_invoke_parts().invoke()
77+
}
78+
79+
fn invoke_signed(self, signers: &[Signer]) -> ProgramResult {
80+
self.into_invoke_parts().invoke_signed(signers)
81+
}
82+
}
83+
84+
mod sealed {
85+
use crate::invoke_parts::{FixedInvokeParts, IntoInvokeParts, SliceInvokeParts};
86+
87+
pub trait Sealed {}
88+
impl<'a, const N: usize> Sealed for FixedInvokeParts<'a, N> {}
89+
impl<'a> Sealed for SliceInvokeParts<'a> {}
90+
impl<T> Sealed for T where T: IntoInvokeParts {}
91+
}

programs/system/src/invoker.rs

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
use core::marker::PhantomData;
2+
3+
use pinocchio::{
4+
account_info::AccountInfo,
5+
instruction::{AccountMeta, Instruction, Signer},
6+
pubkey::Pubkey,
7+
ProgramResult,
8+
};
9+
10+
pub type ConstAccounts<'a, const ACCOUNTS_LEN: usize> = [&'a AccountInfo; ACCOUNTS_LEN];
11+
pub type SliceAccounts<'a> = [&'a AccountInfo];
12+
13+
mod sealed {
14+
pub trait Sealed {}
15+
16+
impl<'a, const ACCOUNTS_LEN: usize> Sealed for super::ConstAccounts<'a, ACCOUNTS_LEN> {}
17+
impl<'a> Sealed for super::SliceAccounts<'a> {}
18+
impl<'a, T, Account> Sealed for super::Invoker<&'a T, Account> {}
19+
impl<T> Sealed for T where T: super::CanInvoke {}
20+
}
21+
22+
pub trait AccountType: sealed::Sealed {}
23+
24+
impl<'a, const ACCOUNTS_LEN: usize> AccountType for ConstAccounts<'a, ACCOUNTS_LEN> {}
25+
impl<'a> AccountType for SliceAccounts<'a> {}
26+
27+
pub trait CanInvoke {
28+
type Accounts: AccountType;
29+
30+
fn invoke_via(
31+
&self,
32+
invoke: impl FnOnce(
33+
/* program_id: */ &Pubkey,
34+
/* accounts: */ &Self::Accounts,
35+
/* account_metas: */ &[AccountMeta],
36+
/* data: */ &[u8],
37+
) -> ProgramResult,
38+
) -> ProgramResult;
39+
40+
#[inline]
41+
fn as_invoker<'a>(&'a self) -> Invoker<&'a Self, &'a Self::Accounts>
42+
where
43+
Self: Sized,
44+
{
45+
Invoker {
46+
inner: self,
47+
account_ty: PhantomData,
48+
}
49+
}
50+
}
51+
52+
pub trait Invoke: sealed::Sealed {
53+
fn invoke(&self) -> ProgramResult;
54+
fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult;
55+
}
56+
57+
pub struct Invoker<T, Account> {
58+
inner: T,
59+
account_ty: PhantomData<Account>,
60+
}
61+
62+
impl<'a, const ACCOUNTS_LEN: usize, T> Invoke for Invoker<&'a T, &ConstAccounts<'a, ACCOUNTS_LEN>>
63+
where
64+
T: CanInvoke<Accounts = ConstAccounts<'a, ACCOUNTS_LEN>>,
65+
{
66+
#[inline]
67+
fn invoke(&self) -> ProgramResult {
68+
self.inner
69+
.invoke_via(|program_id, accounts, account_metas, data| {
70+
let instruction = Instruction {
71+
program_id: program_id,
72+
accounts: &account_metas,
73+
data: data,
74+
};
75+
pinocchio::cpi::invoke(&instruction, accounts)
76+
})
77+
}
78+
79+
#[inline]
80+
fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
81+
self.inner
82+
.invoke_via(|program_id, accounts, account_metas, data| {
83+
let instruction = Instruction {
84+
program_id: program_id,
85+
accounts: &account_metas,
86+
data: data,
87+
};
88+
pinocchio::cpi::invoke_signed(&instruction, accounts, signers)
89+
})
90+
}
91+
}
92+
93+
impl<'a, T> Invoke for Invoker<&'a T, &SliceAccounts<'a>>
94+
where
95+
T: CanInvoke<Accounts = SliceAccounts<'a>>,
96+
{
97+
#[inline]
98+
fn invoke(&self) -> ProgramResult {
99+
self.inner
100+
.invoke_via(|program_id, accounts, account_metas, data| {
101+
let instruction = Instruction {
102+
program_id: program_id,
103+
accounts: &account_metas,
104+
data: data,
105+
};
106+
pinocchio::cpi::slice_invoke(&instruction, accounts)
107+
})
108+
}
109+
110+
#[inline]
111+
fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
112+
self.inner
113+
.invoke_via(|program_id, accounts, account_metas, data| {
114+
let instruction = Instruction {
115+
program_id: program_id,
116+
accounts: &account_metas,
117+
data: data,
118+
};
119+
pinocchio::cpi::slice_invoke_signed(&instruction, accounts, signers)
120+
})
121+
}
122+
}

0 commit comments

Comments
 (0)