use crate::address::Address;
use crate::error::ProgramError;
use crate::project::Projectable;
#[cfg(feature = "cpi")]
use crate::instruction::{InstructionView, Signer};
pub const MAX_RETURN_DATA: usize = 1024;
pub struct ReturnData {
buf: [u8; MAX_RETURN_DATA],
len: usize,
program_id: Address,
}
impl ReturnData {
#[inline(always)]
pub fn data(&self) -> &[u8] {
&self.buf[..self.len]
}
#[inline(always)]
pub fn program_id(&self) -> &Address {
&self.program_id
}
#[inline(always)]
pub fn len(&self) -> usize {
self.len
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub fn as_type<T: Projectable>(&self) -> Result<&T, ProgramError> {
let size = core::mem::size_of::<T>();
if self.len < size {
return Err(ProgramError::AccountDataTooSmall);
}
let align = core::mem::align_of::<T>();
let ptr = self.buf.as_ptr();
if align > 1 && (ptr as usize) % align != 0 {
return Err(ProgramError::InvalidAccountData);
}
Ok(unsafe { &*(ptr as *const T) })
}
#[inline]
pub fn as_u64(&self) -> Result<u64, ProgramError> {
if self.len < 8 {
return Err(ProgramError::AccountDataTooSmall);
}
let mut bytes = [0u8; 8];
bytes.copy_from_slice(&self.buf[..8]);
Ok(u64::from_le_bytes(bytes))
}
#[inline]
pub fn as_u32(&self) -> Result<u32, ProgramError> {
if self.len < 4 {
return Err(ProgramError::AccountDataTooSmall);
}
let mut bytes = [0u8; 4];
bytes.copy_from_slice(&self.buf[..4]);
Ok(u32::from_le_bytes(bytes))
}
}
#[inline]
pub fn get_return_data() -> Option<ReturnData> {
#[allow(unused_mut)]
let mut rd = ReturnData {
buf: [0u8; MAX_RETURN_DATA],
len: 0,
program_id: Address::default(),
};
#[cfg(target_os = "solana")]
{
let actual_len = unsafe {
crate::syscalls::sol_get_return_data(
rd.buf.as_mut_ptr(),
MAX_RETURN_DATA as u64,
rd.program_id.0.as_mut_ptr(),
)
};
rd.len = (actual_len as usize).min(MAX_RETURN_DATA);
}
#[cfg(not(target_os = "solana"))]
{
}
if rd.len == 0 {
None
} else {
Some(rd)
}
}
#[cfg(feature = "cpi")]
#[inline]
pub fn invoke_and_read<'a, T: Projectable, const ACCOUNTS: usize>(
instruction: &InstructionView,
account_views: &[&crate::account_view::AccountView; ACCOUNTS],
signers_seeds: &[Signer],
) -> Result<ReturnData, ProgramError> {
crate::cpi::invoke_signed::<ACCOUNTS>(instruction, account_views, signers_seeds)?;
get_return_data().ok_or(ProgramError::InvalidAccountData)
}