nitrate/lib.rs
1#![allow(clippy::missing_safety_doc)]
2
3extern crate nitrate_macro;
4pub use nitrate_macro::*;
5
6pub mod program {
7 pub use nitrate_program::*;
8}
9
10/// Declare the program entrypoint and set up global handlers.
11///
12/// The main difference from the standard `entrypoint!` macro is that this macro represents an
13/// entrypoint that does not perform allocattions or copies when reading the input buffer.
14///
15/// This macro emits the common boilerplate necessary to begin program execution, calling a
16/// provided function to process the program instruction supplied by the runtime, and reporting
17/// its result to the runtime.
18///
19/// It also sets up a [global allocator] and [panic handler], using the [`custom_heap_default`]
20/// and [`custom_panic_default`] macros from the [`solana_program`] crate.
21///
22/// [`custom_heap_default`]: https://docs.rs/solana-program/latest/solana_program/macro.custom_heap_default.html
23/// [`custom_panic_default`]: https://docs.rs/solana-program/latest/solana_program/macro.custom_panic_default.html
24/// [`solana_program`]: https://docs.rs/solana-program/latest/solana_program/index.html
25///
26/// The first argument is the name of a function with this type signature:
27///
28/// ```ignore
29/// fn process_instruction(
30/// program_id: &Pubkey, // Public key of the account the program was loaded into
31/// accounts: &[AccountInfo], // All accounts required to process the instruction
32/// instruction_data: &[u8], // Serialized instruction-specific data
33/// ) -> ProgramResult;
34/// ```
35///
36/// The second argument is the maximum number of accounts that the program is expecting. A program
37/// can receive more than the specified maximum, but any account exceeding the maximum will be
38/// ignored.
39///
40/// # Examples
41///
42/// Defining an entrypoint which reads up to 10 accounts and making it conditional on the
43/// `no-entrypoint` feature. Although the `entrypoint` module is written inline in this example,
44/// it is common to put it into its own file.
45///
46/// ```no_run
47/// #[cfg(not(feature = "no-entrypoint"))]
48/// pub mod entrypoint {
49///
50/// use nitrate::{entrypoint, program::AccountInfo};
51/// use solana_program::{
52/// entrypoint::ProgramResult,
53/// msg,
54/// pubkey::Pubkey,
55/// };
56///
57/// entrypoint!(process_instruction, 10);
58///
59/// pub fn process_instruction(
60/// program_id: &Pubkey,
61/// accounts: &[AccountInfo],
62/// instruction_data: &[u8],
63/// ) -> ProgramResult {
64/// msg!("Hello from my program!");
65///
66/// Ok(())
67/// }
68///
69/// }
70/// ```
71#[macro_export]
72macro_rules! entrypoint {
73 ( $process_instruction:ident, $maximum:literal ) => {
74 #[no_mangle]
75 pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64 {
76 // create an array of uninitialized account infos; it is safe to `assume_init` since
77 // we are claiming that the aray of `MaybeUninit` is initialized and `MaybeUniint` do
78 // not require initialization
79 let mut accounts: [std::mem::MaybeUninit<$crate::program::AccountInfo>; $maximum] =
80 std::mem::MaybeUninit::uninit().assume_init();
81
82 let (program_id, count, instruction_data) =
83 $crate::program::deserialize::<$maximum>(input, accounts.as_mut_ptr());
84
85 // call the program's entrypoint passing `count` account infos; we know that
86 // they are initialized so we cast the pointer to a slice of `[AccountInfo]`
87 match $process_instruction(
88 &program_id,
89 std::slice::from_raw_parts(accounts.as_ptr() as _, count),
90 &instruction_data,
91 ) {
92 Ok(()) => solana_program::entrypoint::SUCCESS,
93 Err(error) => error.into(),
94 }
95 }
96
97 solana_program::custom_heap_default!();
98 solana_program::custom_panic_default!();
99 };
100}