hopper_native/
return_data.rs1use crate::address::Address;
8use crate::error::ProgramError;
9use crate::project::Projectable;
10
11#[cfg(feature = "cpi")]
12use crate::instruction::{InstructionView, Signer};
13
14pub const MAX_RETURN_DATA: usize = 1024;
16
17pub struct ReturnData {
19 buf: [u8; MAX_RETURN_DATA],
21 len: usize,
23 program_id: Address,
25}
26
27impl ReturnData {
28 #[inline(always)]
30 pub fn data(&self) -> &[u8] {
31 &self.buf[..self.len]
32 }
33
34 #[inline(always)]
36 pub fn program_id(&self) -> &Address {
37 &self.program_id
38 }
39
40 #[inline(always)]
42 pub fn len(&self) -> usize {
43 self.len
44 }
45
46 #[inline(always)]
48 pub fn is_empty(&self) -> bool {
49 self.len == 0
50 }
51
52 #[inline]
57 pub fn as_type<T: Projectable>(&self) -> Result<&T, ProgramError> {
58 let size = core::mem::size_of::<T>();
59 if self.len < size {
60 return Err(ProgramError::AccountDataTooSmall);
61 }
62
63 let align = core::mem::align_of::<T>();
64 let ptr = self.buf.as_ptr();
65 if align > 1 && (ptr as usize) % align != 0 {
66 return Err(ProgramError::InvalidAccountData);
67 }
68
69 Ok(unsafe { &*(ptr as *const T) })
70 }
71
72 #[inline]
74 pub fn as_u64(&self) -> Result<u64, ProgramError> {
75 if self.len < 8 {
76 return Err(ProgramError::AccountDataTooSmall);
77 }
78 let mut bytes = [0u8; 8];
79 bytes.copy_from_slice(&self.buf[..8]);
80 Ok(u64::from_le_bytes(bytes))
81 }
82
83 #[inline]
85 pub fn as_u32(&self) -> Result<u32, ProgramError> {
86 if self.len < 4 {
87 return Err(ProgramError::AccountDataTooSmall);
88 }
89 let mut bytes = [0u8; 4];
90 bytes.copy_from_slice(&self.buf[..4]);
91 Ok(u32::from_le_bytes(bytes))
92 }
93}
94
95#[inline]
99pub fn get_return_data() -> Option<ReturnData> {
100 #[allow(unused_mut)]
101 let mut rd = ReturnData {
102 buf: [0u8; MAX_RETURN_DATA],
103 len: 0,
104 program_id: Address::default(),
105 };
106
107 #[cfg(target_os = "solana")]
108 {
109 let actual_len = unsafe {
110 crate::syscalls::sol_get_return_data(
111 rd.buf.as_mut_ptr(),
112 MAX_RETURN_DATA as u64,
113 rd.program_id.0.as_mut_ptr(),
114 )
115 };
116 rd.len = (actual_len as usize).min(MAX_RETURN_DATA);
117 }
118
119 #[cfg(not(target_os = "solana"))]
120 {
121 }
123
124 if rd.len == 0 {
125 None
126 } else {
127 Some(rd)
128 }
129}
130
131#[cfg(feature = "cpi")]
147#[inline]
148pub fn invoke_and_read<'a, T: Projectable, const ACCOUNTS: usize>(
149 instruction: &InstructionView,
150 account_views: &[&crate::account_view::AccountView; ACCOUNTS],
151 signers_seeds: &[Signer],
152) -> Result<ReturnData, ProgramError> {
153 crate::cpi::invoke_signed::<ACCOUNTS>(instruction, account_views, signers_seeds)?;
154
155 get_return_data().ok_or(ProgramError::InvalidAccountData)
156}