#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]
use {solana_address::Address, solana_program_error::ProgramError};
#[doc(hidden)]
pub mod __private {
pub use {crate::get_sysvar_unchecked, solana_program_error::ProgramError};
}
const SUCCESS: u64 = 0;
const OFFSET_LENGTH_EXCEEDS_SYSVAR: u64 = 1;
const SYSVAR_NOT_FOUND: u64 = 2;
pub trait GetSysvar: Sized {
fn get() -> Result<Self, ProgramError> {
Err(ProgramError::UnsupportedSysvar)
}
}
pub fn get_sysvar(
dst: &mut [u8],
sysvar_id: &Address,
offset: u64,
length: u64,
) -> Result<(), ProgramError> {
if dst.len() < length as usize {
return Err(ProgramError::InvalidArgument);
}
let sysvar_id = sysvar_id as *const _ as *const u8;
let var_addr = dst as *mut _ as *mut u8;
match sol_get_sysvar(sysvar_id, var_addr, offset, length) {
SUCCESS => Ok(()),
OFFSET_LENGTH_EXCEEDS_SYSVAR => Err(ProgramError::InvalidArgument),
_ => Err(ProgramError::UnsupportedSysvar),
}
}
#[doc(hidden)]
pub unsafe fn get_sysvar_unchecked(
var_addr: *mut u8,
sysvar_id: *const u8,
offset: u64,
length: u64,
) -> Result<(), ProgramError> {
match sol_get_sysvar(sysvar_id, var_addr, offset, length) {
SUCCESS => Ok(()),
OFFSET_LENGTH_EXCEEDS_SYSVAR => Err(ProgramError::InvalidArgument),
SYSVAR_NOT_FOUND => Err(ProgramError::UnsupportedSysvar),
_ => Err(ProgramError::UnsupportedSysvar),
}
}
fn sol_get_sysvar(sysvar_id: *const u8, var_addr: *mut u8, offset: u64, length: u64) -> u64 {
#[cfg(target_os = "solana")]
unsafe {
solana_define_syscall::definitions::sol_get_sysvar(sysvar_id, var_addr, offset, length)
}
#[cfg(not(target_os = "solana"))]
{
let _ = (sysvar_id, var_addr, offset, length); solana_program_error::UNSUPPORTED_SYSVAR
}
}
#[macro_export]
macro_rules! impl_get_sysvar {
($sysvar_id:expr, $padding:literal) => {
fn get() -> Result<Self, $crate::__private::ProgramError> {
let mut var = core::mem::MaybeUninit::<Self>::uninit();
let var_addr = var.as_mut_ptr() as *mut u8;
let length = core::mem::size_of::<Self>().saturating_sub($padding);
let sysvar_id_ptr = (&$sysvar_id) as *const _ as *const u8;
let result = unsafe {
var_addr.add(length).write_bytes(0, $padding);
$crate::__private::get_sysvar_unchecked(var_addr, sysvar_id_ptr, 0, length as u64)
};
match result {
Ok(()) => Ok(unsafe { var.assume_init() }),
Err(_) => Err($crate::__private::ProgramError::UnsupportedSysvar),
}
}
};
($sysvar_id:expr) => {
$crate::impl_get_sysvar!($sysvar_id, 0);
};
}