1extern crate proc_macro;
2extern crate syn;
3
4use proc_macro::TokenStream;
5use quote::quote;
6use syn::{parse_macro_input, ItemStruct};
7
8#[proc_macro_attribute]
39pub fn game_handler(_metadata: TokenStream, input: TokenStream) -> TokenStream {
40 let s = parse_macro_input!(input as ItemStruct);
41 let s_idt = s.clone().ident;
42
43 TokenStream::from(quote! {
44
45 #s
46
47 pub fn read_ptr<T: BorshDeserialize>(ptr: &mut *mut u8, size: u32) -> Option<T> {
48 let slice = unsafe { core::slice::from_raw_parts_mut(*ptr, size as _) };
49 if let Ok(parsed) = T::try_from_slice(&slice) {
50 *ptr = unsafe { ptr.add(size as _) };
51 Some(parsed)
52 } else {
53 None
54 }
55 }
56
57 pub fn write_ptr<T: BorshSerialize>(ptr: &mut *mut u8, data: T) -> u32 {
58 if let Ok(vec) = data.try_to_vec() {
59 unsafe { std::ptr::copy(vec.as_ptr(), *ptr, vec.len()) }
60 vec.len() as _
61 } else {
62 0
63 }
64 }
65
66 #[no_mangle]
67 pub extern "C" fn handle_event(effect_size: u32, event_size: u32) -> u32 {
68 let mut ptr = 1 as *mut u8;
69 let mut effect: race_api::effect::Effect = if let Some(effect) = read_ptr(&mut ptr, effect_size) {
70 effect
71 } else {
72 return 1
73 };
74 let event: race_api::event::Event = if let Some(event) = read_ptr(&mut ptr, event_size) {
75 event
76 } else {
77 return 2
78 };
79
80 let mut handler: #s_idt = effect.__handler_state();
81 match handler.handle_event(&mut effect, event) {
82 Ok(_) => effect.__set_handler_state(&handler),
83 Err(e) => effect.__set_error(e),
84 }
85
86 if effect.is_checkpoint {
87 match handler.into_checkpoint() {
88 Ok(checkpoint_state) => effect.__set_checkpoint(checkpoint_state),
89 Err(e) => effect.__set_error(e),
90 }
91 }
92
93 let mut ptr = 1 as *mut u8;
94 write_ptr(&mut ptr, effect)
95 }
96
97 #[no_mangle]
98 pub extern "C" fn init_state(effect_size: u32, init_account_size: u32) -> u32 {
99 let mut ptr = 1 as *mut u8;
100 let mut effect: race_api::effect::Effect = if let Some(effect) = read_ptr(&mut ptr, effect_size) {
101 effect
102 } else {
103 return 1
104 };
105 let init_account: race_api::engine::InitAccount = if let Some(init_account) = read_ptr(&mut ptr, init_account_size) {
106 init_account
107 } else {
108 return 2
109 };
110 match #s_idt::init_state(&mut effect, init_account) {
111 Ok(handler) => effect.__set_handler_state(&handler),
112 Err(e) => effect.__set_error(e),
113 }
114 let mut ptr = 1 as *mut u8;
115 write_ptr(&mut ptr, effect)
116 }
117 })
118}