Skip to content

Commit 3d66f5d

Browse files
committed
all three impls
1 parent 566d41a commit 3d66f5d

File tree

4 files changed

+338
-122
lines changed

4 files changed

+338
-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: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
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 struct InvokeParts<Accounts, Metas, Data> {
14+
pub program_id: Pubkey,
15+
pub accounts: Accounts,
16+
pub account_metas: Metas,
17+
pub instruction_data: Data,
18+
}
19+
20+
impl<Accounts, Metas, Data> InvokeParts<Accounts, Metas, Data> {
21+
pub fn new(
22+
program_id: Pubkey,
23+
accounts: Accounts,
24+
account_metas: Metas,
25+
instruction_data: Data,
26+
) -> Self {
27+
Self {
28+
program_id,
29+
accounts,
30+
account_metas,
31+
instruction_data,
32+
}
33+
}
34+
}
35+
36+
impl SliceInvokeParts<'_> {
37+
pub fn invoke(self) -> ProgramResult {
38+
self.invoke_signed(&[])
39+
}
40+
41+
pub fn invoke_signed(self, signers: &[Signer]) -> ProgramResult {
42+
cpi::slice_invoke_signed(
43+
&Instruction {
44+
program_id: &self.program_id,
45+
data: &self.instruction_data,
46+
accounts: &self.account_metas,
47+
},
48+
self.accounts,
49+
signers,
50+
)
51+
}
52+
}
53+
54+
impl<const N: usize> FixedInvokeParts<'_, N> {
55+
pub fn invoke(self) -> ProgramResult {
56+
self.invoke_signed(&[])
57+
}
58+
59+
pub fn invoke_signed(self, signers: &[Signer]) -> ProgramResult {
60+
cpi::invoke_signed(
61+
&Instruction {
62+
program_id: &self.program_id,
63+
data: &self.instruction_data,
64+
accounts: &self.account_metas,
65+
},
66+
self.accounts,
67+
signers,
68+
)
69+
}
70+
}
71+
72+
pub trait InvokePartsType: sealed::Sealed {}
73+
impl InvokePartsType for SliceInvokeParts<'_> {}
74+
impl<const N: usize> InvokePartsType for FixedInvokeParts<'_, N> {}
75+
76+
pub trait IntoInvokeParts {
77+
type Output: InvokePartsType;
78+
79+
fn into_invoke_parts(self) -> Self::Output;
80+
}
81+
82+
pub trait Invoke: sealed::Sealed {
83+
fn invoke(self) -> ProgramResult;
84+
fn invoke_signed(self, signers: &[Signer]) -> ProgramResult;
85+
}
86+
87+
impl Invoke for SliceInvokeParts<'_> {
88+
fn invoke(self) -> ProgramResult {
89+
self.invoke()
90+
}
91+
92+
fn invoke_signed(self, signers: &[Signer]) -> ProgramResult {
93+
self.invoke_signed(signers)
94+
}
95+
}
96+
97+
impl<const N: usize> Invoke for FixedInvokeParts<'_, N> {
98+
fn invoke(self) -> ProgramResult {
99+
self.invoke()
100+
}
101+
102+
fn invoke_signed(self, signers: &[Signer]) -> ProgramResult {
103+
self.invoke_signed(signers)
104+
}
105+
}
106+
107+
impl<T> Invoke for T
108+
where
109+
T: IntoInvokeParts,
110+
T::Output: Invoke,
111+
{
112+
fn invoke(self) -> ProgramResult {
113+
self.into_invoke_parts().invoke()
114+
}
115+
116+
fn invoke_signed(self, signers: &[Signer]) -> ProgramResult {
117+
self.into_invoke_parts().invoke_signed(signers)
118+
}
119+
}
120+
121+
mod sealed {
122+
use crate::invoke_parts::{FixedInvokeParts, IntoInvokeParts, SliceInvokeParts};
123+
124+
pub trait Sealed {}
125+
impl<'a, const N: usize> Sealed for FixedInvokeParts<'a, N> {}
126+
impl<'a> Sealed for SliceInvokeParts<'a> {}
127+
impl<T> Sealed for T where T: IntoInvokeParts {}
128+
}

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)