cfx_core/
invoker.rs

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(); // cleanup memory after a call
141
142    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
206// TODO: Result ...
207pub 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
242/// A FiveM runtime native. Registers current resource as an event handler.
243/// Means that if someone triggers an event with this name the resource will be notified.
244pub fn register_resource_as_event_handler(event: &str) -> Result<(), InvokeError> {
245    invoke(0xD233A168, &[Val::String(event)])
246}
247
248/// Gets a name of the current resource.
249pub fn current_resource_name() -> Result<String, InvokeError> {
250    invoke(0xE5E9EBBB, &[])
251}