tape_api/
macros.rs

1#[macro_export]
2macro_rules! state {
3    // $acct_ty is your AccountType enum variant, $data_ty is the struct name
4    ($acct_ty:ident, $data_ty:ident) => {
5        impl $data_ty {
6            /// 8 bytes for the discriminator + the POD struct size
7            pub const fn get_size() -> usize {
8                8 + core::mem::size_of::<Self>()
9            }
10
11            /// Immutably unpack from a raw account data slice
12            pub fn unpack(data: &[u8]) -> Result<&Self, ProgramError> {
13                let data = &data[..Self::get_size()];
14                Self::try_from_bytes(data)
15            }
16
17            /// Mutably unpack from a raw account data slice
18            pub fn unpack_mut(data: &mut [u8]) -> Result<&mut Self, ProgramError> {
19                let data = &mut data[..Self::get_size()];
20                Self::try_from_bytes_mut(data)
21            }
22        }
23
24        // steel account macro
25        account!($acct_ty, $data_ty);
26    };
27}
28
29#[macro_export]
30macro_rules! impl_to_bytes {
31    ($struct_name:ident, $discriminator_name:ident) => {
32        impl $struct_name {
33            pub fn to_bytes(&self) -> Vec<u8> {
34                let mut discriminator = [0u8; 8];
35                discriminator[0] = $discriminator_name::$struct_name as u8;
36                [
37                    discriminator.to_vec(),
38                    bytemuck::bytes_of(self).to_vec(),
39                ]
40                .concat()
41            }
42        }
43    };
44}
45
46#[macro_export]
47macro_rules! impl_try_from_bytes {
48    ($struct_name:ident, $discriminator_name:ident) => {
49        impl $struct_name {
50            pub fn try_from_bytes(data: &[u8]) -> std::io::Result<&Self> {
51                if data.len() < 8 {
52                    return Err(std::io::Error::new(
53                        std::io::ErrorKind::InvalidData,
54                        "Data too short for discriminator",
55                    ));
56                }
57                let discriminator = data[0];
58                if discriminator != $discriminator_name::$struct_name as u8 {
59                    return Err(std::io::Error::new(
60                        std::io::ErrorKind::InvalidData,
61                        format!(
62                            "Invalid discriminator: expected {}, got {}",
63                            $discriminator_name::$struct_name as u8,
64                            discriminator
65                        ),
66                    ));
67                }
68                let struct_size = std::mem::size_of::<Self>();
69                if data.len() < 8 + struct_size {
70                    return Err(std::io::Error::new(
71                        std::io::ErrorKind::InvalidData,
72                        format!(
73                            "Data too short: expected at least {} bytes, got {}",
74                            8 + struct_size,
75                            data.len()
76                        ),
77                    ));
78                }
79                bytemuck::try_from_bytes::<Self>(&data[8..8 + struct_size]).map_err(|e| {
80                    std::io::Error::new(std::io::ErrorKind::InvalidData, e.to_string())
81                })
82            }
83        }
84    };
85}
86
87#[macro_export]
88macro_rules! event {
89    ($discriminator_name:ident, $struct_name:ident) => {
90        $crate::impl_to_bytes!($struct_name, $discriminator_name);
91        $crate::impl_try_from_bytes!($struct_name, $discriminator_name);
92
93        impl $struct_name {
94            const DISCRIMINATOR_SIZE: usize = 8;
95
96            pub fn size_of() -> usize {
97                core::mem::size_of::<Self>() + Self::DISCRIMINATOR_SIZE
98            }
99
100            pub fn log(&self) {
101                solana_program::log::sol_log_data(&[&self.to_bytes()]);
102            }
103        }
104    };
105}