use core::mem::MaybeUninit;
use crate::account_view::AccountView;
use crate::address::Address;
#[inline(always)]
pub unsafe fn process_entrypoint<const MAX: usize>(
input: *mut u8,
process_instruction: fn(&Address, &[AccountView], &[u8]) -> crate::ProgramResult,
) -> u64 {
const UNINIT: MaybeUninit<AccountView> = MaybeUninit::uninit();
let mut accounts = [UNINIT; 254];
let (program_id, count, instruction_data) =
unsafe { crate::raw_input::deserialize_accounts::<254>(input, &mut accounts) };
let effective_count = count.min(MAX);
let account_slice = unsafe {
core::slice::from_raw_parts(accounts.as_ptr() as *const AccountView, effective_count)
};
match process_instruction(&program_id, account_slice, instruction_data) {
Ok(()) => crate::SUCCESS,
Err(error) => error.into(),
}
}
#[macro_export]
macro_rules! hopper_program_entrypoint {
( $process_instruction:expr ) => {
$crate::hopper_program_entrypoint!($process_instruction, { $crate::MAX_TX_ACCOUNTS });
};
( $process_instruction:expr, $maximum:expr ) => {
#[no_mangle]
pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64 {
const UNINIT: core::mem::MaybeUninit<$crate::AccountView> =
core::mem::MaybeUninit::<$crate::AccountView>::uninit();
let mut accounts = [UNINIT; $maximum];
let (program_id, count, instruction_data) = unsafe {
$crate::raw_input::deserialize_accounts::<$maximum>(input, &mut accounts)
};
match $process_instruction(
&program_id,
unsafe { core::slice::from_raw_parts(accounts.as_ptr() as _, count) },
instruction_data,
) {
Ok(()) => $crate::SUCCESS,
Err(error) => error.into(),
}
}
};
}
#[macro_export]
macro_rules! program_entrypoint {
( $process_instruction:expr ) => {
$crate::hopper_program_entrypoint!($process_instruction);
};
( $process_instruction:expr, $maximum:expr ) => {
$crate::hopper_program_entrypoint!($process_instruction, $maximum);
};
}
#[macro_export]
macro_rules! hopper_fast_entrypoint {
( $process_instruction:expr ) => {
$crate::hopper_fast_entrypoint!($process_instruction, { $crate::MAX_TX_ACCOUNTS });
};
( $process_instruction:expr, $maximum:expr ) => {
#[no_mangle]
pub unsafe extern "C" fn entrypoint(input: *mut u8, ix_data: *const u8) -> u64 {
const UNINIT: core::mem::MaybeUninit<$crate::AccountView> =
core::mem::MaybeUninit::<$crate::AccountView>::uninit();
let mut accounts = [UNINIT; $maximum];
let ix_len = unsafe { *(ix_data.sub(8) as *const u64) as usize };
let instruction_data: &'static [u8] =
unsafe { core::slice::from_raw_parts(ix_data, ix_len) };
let program_id =
unsafe { core::ptr::read(ix_data.add(ix_len) as *const $crate::Address) };
let (program_id, count, instruction_data) = unsafe {
$crate::raw_input::deserialize_accounts_fast::<$maximum>(
input,
&mut accounts,
instruction_data,
program_id,
)
};
match $process_instruction(
&program_id,
unsafe { core::slice::from_raw_parts(accounts.as_ptr() as _, count) },
instruction_data,
) {
Ok(()) => $crate::SUCCESS,
Err(error) => error.into(),
}
}
};
}
#[macro_export]
macro_rules! fast_entrypoint {
( $process_instruction:expr ) => {
$crate::hopper_fast_entrypoint!($process_instruction);
};
( $process_instruction:expr, $maximum:expr ) => {
$crate::hopper_fast_entrypoint!($process_instruction, $maximum);
};
}
#[macro_export]
macro_rules! hopper_lazy_entrypoint {
( $process:expr ) => {
#[no_mangle]
pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64 {
let mut ctx = unsafe { $crate::lazy::lazy_deserialize(input) };
match $process(&mut ctx) {
Ok(()) => $crate::SUCCESS,
Err(error) => error.into(),
}
}
};
}
#[macro_export]
macro_rules! lazy_entrypoint {
( $process:expr ) => {
$crate::hopper_lazy_entrypoint!($process);
};
}
#[macro_export]
macro_rules! no_allocator {
() => {
#[cfg(target_os = "solana")]
mod __hopper_allocator {
struct NoAlloc;
unsafe impl core::alloc::GlobalAlloc for NoAlloc {
unsafe fn alloc(&self, _layout: core::alloc::Layout) -> *mut u8 {
core::arch::asm!("mov r0, 1", "exit", options(noreturn));
}
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: core::alloc::Layout) {}
}
#[global_allocator]
static ALLOCATOR: NoAlloc = NoAlloc;
}
};
}
#[macro_export]
macro_rules! nostd_panic_handler {
() => {
#[cfg(target_os = "solana")]
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
unsafe { core::arch::asm!("mov r0, 1", "exit", options(noreturn)) };
}
};
}