solana_sdk/builtins.rs
1//! Safecoin builtin helper macros
2
3#[rustversion::since(1.46.0)]
4#[macro_export]
5macro_rules! declare_builtin_name {
6 ($name:ident, $id:path, $entrypoint:expr) => {
7 #[macro_export]
8 macro_rules! $name {
9 () => {
10 // Subtle:
11 // The outer `declare_builtin_name!` macro may be expanded in another
12 // crate, causing the macro `$name!` to be defined in that
13 // crate. We want to emit a call to `$crate::id()`, and have
14 // `$crate` be resolved in the crate where `$name!` gets defined,
15 // *not* in this crate (where `declare_builtin_name! is defined).
16 //
17 // When a macro_rules! macro gets expanded, any $crate tokens
18 // in its output will be 'marked' with the crate they were expanded
19 // from. This includes nested macros like our macro `$name` - even
20 // though it looks like a separate macro, Rust considers it to be
21 // just another part of the output of `declare_program!`.
22 //
23 // We pass `$name` as the second argument to tell `respan!` to
24 // apply use the `Span` of `$name` when resolving `$crate::id`.
25 // This causes `$crate` to behave as though it was written
26 // at the same location as the `$name` value passed
27 // to `declare_builtin_name!` (e.g. the 'foo' in
28 // `declare_builtin_name(foo)`
29 //
30 // See the `respan!` macro for more details.
31 // This should use `crate::respan!` once
32 // https://github.com/rust-lang/rust/pull/72121 is merged:
33 // see https://github.com/fair-exchange/safecoin/issues/10933.
34 // For now, we need to use `::solana_sdk`
35 //
36 // `respan!` respans the path `$crate::id`, which we then call (hence the extra
37 // parens)
38 (
39 stringify!($name).to_string(),
40 ::solana_sdk::respan!($crate::$id, $name)(),
41 $entrypoint,
42 )
43 };
44 }
45 };
46}
47
48#[rustversion::not(since(1.46.0))]
49#[macro_export]
50macro_rules! declare_builtin_name {
51 ($name:ident, $id:path, $entrypoint:expr) => {
52 #[macro_export]
53 macro_rules! $name {
54 () => {
55 (stringify!($name).to_string(), $crate::$id(), $entrypoint)
56 };
57 }
58 };
59}
60
61/// Convenience macro to declare a builtin
62///
63/// bs58_string: bs58 string representation the program's id
64/// name: Name of the program
65/// entrypoint: Program's entrypoint, must be of `type Entrypoint`
66/// id: Path to the program id access function, used if this macro is not
67/// called in `src/lib`
68///
69/// # Examples
70///
71/// ```
72/// use std::str::FromStr;
73/// // wrapper is used so that the macro invocation occurs in the item position
74/// // rather than in the statement position which isn't allowed.
75/// mod item_wrapper {
76/// use solana_sdk::keyed_account::KeyedAccount;
77/// use solana_sdk::instruction::InstructionError;
78/// use solana_sdk::pubkey::Pubkey;
79/// use solana_sdk::declare_builtin;
80///
81/// fn my_process_instruction(
82/// first_instruction_account: usize,
83/// keyed_accounts: &[KeyedAccount],
84/// ) -> Result<(), InstructionError> {
85/// // Process an instruction
86/// Ok(())
87/// }
88///
89/// declare_builtin!(
90/// "My11111111111111111111111111111111111111111",
91/// solana_my_program,
92/// my_process_instruction
93/// );
94///
95/// # }
96/// # use solana_sdk::pubkey::Pubkey;
97/// # use item_wrapper::id;
98/// let my_id = Pubkey::from_str("My11111111111111111111111111111111111111111").unwrap();
99/// assert_eq!(id(), my_id);
100/// ```
101/// ```
102/// use std::str::FromStr;
103/// # // wrapper is used so that the macro invocation occurs in the item position
104/// # // rather than in the statement position which isn't allowed.
105/// # mod item_wrapper {
106/// use solana_sdk::keyed_account::KeyedAccount;
107/// use solana_sdk::instruction::InstructionError;
108/// use solana_sdk::pubkey::Pubkey;
109/// use solana_sdk::declare_builtin;
110///
111/// fn my_process_instruction(
112/// first_instruction_account: usize,
113/// keyed_accounts: &[KeyedAccount],
114/// ) -> Result<(), InstructionError> {
115/// // Process an instruction
116/// Ok(())
117/// }
118///
119/// declare_builtin!(
120/// solana_sdk::system_program::ID,
121/// solana_my_program,
122/// my_process_instruction
123/// );
124/// }
125///
126/// # use item_wrapper::id;
127/// assert_eq!(id(), solana_sdk::system_program::ID);
128/// ```
129#[macro_export]
130macro_rules! declare_builtin {
131 ($bs58_string:expr, $name:ident, $entrypoint:expr) => {
132 $crate::declare_builtin!($bs58_string, $name, $entrypoint, id);
133 };
134 ($bs58_string:expr, $name:ident, $entrypoint:expr, $id:path) => {
135 $crate::declare_id!($bs58_string);
136 $crate::declare_builtin_name!($name, $id, $entrypoint);
137 };
138}