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}