1use crate::{
2 ref_funcs::{ExternRefFunction, RefFunction},
3 types::{call_result, CharPtr, GuestArg, RetVal, ReturnValue, Vector3},
4};
5
6use serde::{de::DeserializeOwned, Serialize};
7use std::cell::RefCell;
8
9const RETVAL_BUFFER_SIZE: usize = 1 << 15;
10
11thread_local! {
12 static RETVAL_BUFFER: RefCell<Vec<u8>> = RefCell::new(vec![0; RETVAL_BUFFER_SIZE]);
13}
14
15pub mod ffi {
16 #[link(wasm_import_module = "host")]
17 extern "C" {
18 pub fn invoke(
19 hash: u64,
20 ptr: *const crate::types::GuestArg,
21 len: usize,
22 retval: *const crate::types::ReturnValue,
23 ) -> i32;
24
25 pub fn invoke_ref_func(
26 ref_name: *const i8,
27 args: *const u8,
28 args_len: usize,
29 buffer: *mut u8,
30 buffer_capacity: usize,
31 ) -> i32;
32 }
33}
34
35#[no_mangle]
36pub extern "C" fn __cfx_extend_retval_buffer(new_size: usize) -> *const u8 {
37 RETVAL_BUFFER.with(|retval| {
38 let mut vec = retval.borrow_mut();
39 vec.resize(new_size, 0);
40
41 vec.as_ptr()
42 })
43}
44
45pub enum Val<'a> {
46 RefInteger(&'a i32),
47 RefFloat(&'a f32),
48 RefLong(&'a i64),
49 RefBool(&'a bool),
50
51 MutRefInteger(&'a mut i32),
52 MutRefFloat(&'a mut f32),
53 MutRefLong(&'a mut i64),
54 MutRefBool(&'a mut bool),
55
56 Integer(i32),
57 Float(f32),
58 Long(i64),
59 Bool(bool),
60
61 Vector3(Vector3),
62 RefVector3(&'a Vector3),
63 MutRefVector3(&'a mut Vector3),
64
65 String(&'a str),
66 Bytes(&'a [u8]),
67 MutBytes(&'a mut [u8]),
68
69 RefFunc(RefFunction),
70}
71
72macro_rules! impl_from {
73 ($type:ty, $val:ident, $ref:ident, $mut:ident) => {
74 impl<'a> From<$type> for Val<'a> {
75 #[inline]
76 fn from(val: $type) -> Val<'a> {
77 Val::$val(val)
78 }
79 }
80
81 impl<'a> From<&'a $type> for Val<'a> {
82 #[inline]
83 fn from(val: &'a $type) -> Val<'a> {
84 Val::$ref(val)
85 }
86 }
87
88 impl<'a> From<&'a mut $type> for Val<'a> {
89 #[inline]
90 fn from(val: &'a mut $type) -> Val<'a> {
91 Val::$mut(val)
92 }
93 }
94 };
95}
96
97impl_from!(i32, Integer, RefInteger, MutRefInteger);
98impl_from!(f32, Float, RefFloat, MutRefFloat);
99impl_from!(i64, Long, RefLong, MutRefLong);
100impl_from!(bool, Bool, RefBool, MutRefBool);
101impl_from!(Vector3, Vector3, RefVector3, MutRefVector3);
102
103impl<'a> From<CharPtr<'a>> for Val<'a> {
104 #[inline]
105 fn from(char_ptr: CharPtr<'a>) -> Self {
106 match char_ptr {
107 CharPtr::Bytes(bytes) => Val::Bytes(bytes),
108 CharPtr::String(str) => Val::String(str),
109 }
110 }
111}
112
113impl<'a> From<RefFunction> for Val<'a> {
114 #[inline]
115 fn from(ref_func: RefFunction) -> Self {
116 Val::RefFunc(ref_func)
117 }
118}
119
120impl<'a> From<&'a [u8]> for Val<'a> {
121 #[inline]
122 fn from(bytes: &'a [u8]) -> Self {
123 Val::Bytes(bytes)
124 }
125}
126
127#[derive(Debug, Clone)]
128pub enum InvokeError {
129 NullResult,
130 NoSpace,
131 Code(i32),
132}
133
134pub fn invoke<'a, Ret, Args>(hash: u64, arguments: Args) -> Result<Ret, InvokeError>
135where
136 Ret: RetVal,
137 Args: IntoIterator<Item = &'a Val<'a>>,
138{
139 let iter = arguments.into_iter();
140 let mut strings = Vec::new(); let args = iter
143 .map(|arg| match arg {
144 Val::Integer(int) => GuestArg::new(int, false),
145 Val::Float(float) => GuestArg::new(float, false),
146 Val::Long(long) => GuestArg::new(long, false),
147 Val::Bool(bool) => GuestArg::new(bool, false),
148 Val::RefInteger(int) => GuestArg::new(*int, true),
149 Val::RefFloat(float) => GuestArg::new(*float, true),
150 Val::RefLong(long) => GuestArg::new(*long, true),
151 Val::RefBool(bool) => GuestArg::new(*bool, true),
152 Val::MutRefInteger(int) => GuestArg::new(*int, true),
153 Val::MutRefFloat(float) => GuestArg::new(*float, true),
154 Val::MutRefLong(long) => GuestArg::new(*long, true),
155 Val::MutRefBool(bool) => GuestArg::new(*bool, true),
156 Val::Vector3(vec) => GuestArg::new(vec, false),
157 Val::RefVector3(vec) => GuestArg::new(*vec, true),
158 Val::MutRefVector3(vec) => GuestArg::new(*vec, true),
159
160 Val::String(string) => {
161 let cstr = std::ffi::CString::new(*string).unwrap();
162 let ptr = cstr.as_bytes_with_nul().as_ptr();
163
164 strings.push(cstr);
165
166 GuestArg::new(unsafe { &*ptr }, true)
167 }
168
169 Val::Bytes(bytes) => GuestArg::new(unsafe { &*bytes.as_ptr() }, true),
170 Val::MutBytes(bytes) => GuestArg::new(unsafe { &*bytes.as_ptr() }, true),
171
172 Val::RefFunc(func) => {
173 let cstr = std::ffi::CString::new(func.name()).unwrap();
174 let ptr = cstr.as_bytes_with_nul().as_ptr();
175
176 strings.push(cstr);
177
178 GuestArg::new(unsafe { &*ptr }, true)
179 }
180 })
181 .collect::<Vec<GuestArg>>();
182
183 RETVAL_BUFFER.with(|buf| unsafe {
184 let retval = ReturnValue::new::<Ret>(&buf.borrow());
185
186 let ret_len = ffi::invoke(hash, args.as_ptr(), args.len(), (&retval) as *const _);
187
188 if ret_len == call_result::NULL_RESULT {
189 return Err(InvokeError::NullResult);
190 }
191
192 if ret_len == call_result::SMALL_RETURN_BUFFER {
193 return Err(InvokeError::NoSpace);
194 }
195
196 if ret_len < call_result::SUCCESS {
197 return Err(InvokeError::Code(ret_len));
198 }
199
200 let read_buf = std::slice::from_raw_parts(buf.borrow().as_ptr(), ret_len as usize);
201
202 Ok(Ret::convert(read_buf))
203 })
204}
205
206pub fn invoke_ref_func<Out, In>(func: &ExternRefFunction, args: In) -> Option<Out>
208where
209 In: Serialize,
210 Out: DeserializeOwned,
211{
212 let ref_name = std::ffi::CString::new(func.name()).ok()?;
213 let args = rmp_serde::to_vec_named(&args).ok()?;
214
215 let (buffer, buffer_capacity) = RETVAL_BUFFER.with(|buf| {
216 let mut buffer = buf.borrow_mut();
217 (buffer.as_mut_ptr(), buffer.capacity())
218 });
219
220 let result = unsafe {
221 ffi::invoke_ref_func(
222 ref_name.as_ptr(),
223 args.as_ptr(),
224 args.len(),
225 buffer,
226 buffer_capacity,
227 )
228 };
229
230 if result < call_result::SUCCESS {
231 return None;
232 }
233
234 RETVAL_BUFFER.with(|buf| {
235 let read_buf =
236 unsafe { std::slice::from_raw_parts(buf.borrow().as_ptr(), result as usize) };
237
238 rmp_serde::decode::from_read(read_buf).ok()
239 })
240}
241
242pub fn register_resource_as_event_handler(event: &str) -> Result<(), InvokeError> {
245 invoke(0xD233A168, &[Val::String(event)])
246}
247
248pub fn current_resource_name() -> Result<String, InvokeError> {
250 invoke(0xE5E9EBBB, &[])
251}