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) })
71 }
72
73 #[inline]
75 pub fn as_u64(&self) -> Result<u64, ProgramError> {
76 if self.len < 8 {
77 return Err(ProgramError::AccountDataTooSmall);
78 }
79 let mut bytes = [0u8; 8];
80 bytes.copy_from_slice(&self.buf[..8]);
81 Ok(u64::from_le_bytes(bytes))
82 }
83
84 #[inline]
86 pub fn as_u32(&self) -> Result<u32, ProgramError> {
87 if self.len < 4 {
88 return Err(ProgramError::AccountDataTooSmall);
89 }
90 let mut bytes = [0u8; 4];
91 bytes.copy_from_slice(&self.buf[..4]);
92 Ok(u32::from_le_bytes(bytes))
93 }
94}
95
96#[inline]
100pub fn get_return_data() -> Option<ReturnData> {
101 #[allow(unused_mut)]
102 let mut rd = ReturnData {
103 buf: [0u8; MAX_RETURN_DATA],
104 len: 0,
105 program_id: Address::default(),
106 };
107
108 #[cfg(target_os = "solana")]
109 {
110 let actual_len = unsafe {
112 crate::syscalls::sol_get_return_data(
113 rd.buf.as_mut_ptr(),
114 MAX_RETURN_DATA as u64,
115 rd.program_id.0.as_mut_ptr(),
116 )
117 };
118 rd.len = (actual_len as usize).min(MAX_RETURN_DATA);
119 }
120
121 #[cfg(not(target_os = "solana"))]
122 {
123 }
125
126 if rd.len == 0 {
127 None
128 } else {
129 Some(rd)
130 }
131}
132
133#[cfg(feature = "cpi")]
149#[inline]
150pub fn invoke_and_read<'a, T: Projectable, const ACCOUNTS: usize>(
151 instruction: &InstructionView,
152 account_views: &[&crate::account_view::AccountView; ACCOUNTS],
153 signers_seeds: &[Signer],
154) -> Result<ReturnData, ProgramError> {
155 crate::cpi::invoke_signed::<ACCOUNTS>(instruction, account_views, signers_seeds)?;
156
157 get_return_data().ok_or(ProgramError::InvalidAccountData)
158}