Skip to content

Commit

Permalink
rework calling squirrel functions
Browse files Browse the repository at this point in the history
  • Loading branch information
catornot committed Feb 12, 2024
1 parent 1a4b6bd commit f4a5796
Show file tree
Hide file tree
Showing 12 changed files with 198 additions and 89 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ default-target = "x86_64-pc-windows-msvc"
targets = ["x86_64-pc-windows-msvc", "x86_64-pc-windows-gnu"] # hopefully docs.rs will still work

[features]
# default = ["async_engine"]
default = ["async_engine"]
async_engine = []
4 changes: 2 additions & 2 deletions rrplug_proc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ pub fn sqfunction(attr: TokenStream, item: TokenStream) -> TokenStream {
} = input;

let stmts = block.stmts;
let mut sub_stms = Vec::new();
let mut sub_stms: Vec<Stmt> = Vec::new();
let ident = &sig.ident;
let input = &sig.inputs;
let input_vec: Vec<FnArg> = input.iter().filter_map(|arg| filter_args(arg)).collect();
Expand Down Expand Up @@ -121,7 +121,7 @@ pub fn sqfunction(attr: TokenStream, item: TokenStream) -> TokenStream {
}
sq_gets_stmts.reverse();
for s in sq_gets_stmts {
sub_stms.insert(0, s);
sub_stms.insert(0, parse(quote! {#[allow(unused_mut)] #s}.into()).unwrap());
}

let mut script_vm: Punctuated<TypePath, Token![|]> = Punctuated::new();
Expand Down
1 change: 1 addition & 0 deletions src/bindings/squirrelclasstypes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ pub type sq_pushassetType =
unsafe extern "C" fn(sqvm: *mut HSquirrelVM, str_: *const SQChar, iLength: SQInteger);
pub type sq_pushvectorType = unsafe extern "C" fn(sqvm: *mut HSquirrelVM, pVec: *const SQFloat);
pub type sq_pushobjectType = unsafe extern "C" fn(sqvm: *mut HSquirrelVM, pVec: *mut SQObject);
pub type sq_pushnullType = unsafe extern "C" fn(sqvm: *mut HSquirrelVM);
pub type sq_getstringType =
unsafe extern "C" fn(sqvm: *mut HSquirrelVM, iStackpos: SQInteger) -> *const SQChar;
pub type sq_getintegerType =
Expand Down
5 changes: 5 additions & 0 deletions src/bindings/squirrelfunctions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ offset_functions! {
sq_pushasset = sq_pushassetType where offset(0x3560);
sq_pushvector = sq_pushvectorType where offset(0x3780);
sq_pushobject = sq_pushobjectType where offset(0x83A0);
sq_pushnull = sq_pushnullType where offset(0x33d0);

sq_raiseerror = sq_raiseerrorType where offset(0x8440);

Expand Down Expand Up @@ -78,6 +79,7 @@ offset_functions! {
sq_pushasset = sq_pushassetType where offset(0x3560);
sq_pushvector = sq_pushvectorType where offset(0x3780);
sq_pushobject = sq_pushobjectType where offset(0x83D0);
sq_pushnull = sq_pushnullType where offset(0x33d0);

sq_raiseerror = sq_raiseerrorType where offset(0x8470);

Expand Down Expand Up @@ -128,6 +130,7 @@ pub struct SquirrelFunctions {
pub sq_pushasset: sq_pushassetType,
pub sq_pushvector: sq_pushvectorType,
pub sq_pushobject: sq_pushobjectType,
pub sq_pushnull: sq_pushnullType,
pub sq_getstring: sq_getstringType,
pub sq_getinteger: sq_getintegerType,
pub sq_getfloat: sq_getfloatType,
Expand Down Expand Up @@ -169,6 +172,7 @@ impl From<&ClientSQFunctions> for SquirrelFunctions {
sq_pushasset: val.sq_pushasset,
sq_pushvector: val.sq_pushvector,
sq_pushobject: val.sq_pushobject,
sq_pushnull: val.sq_pushnull,
sq_getstring: val.sq_getstring,
sq_getinteger: val.sq_getinteger,
sq_getfloat: val.sq_getfloat,
Expand Down Expand Up @@ -212,6 +216,7 @@ impl From<&ServerSQFunctions> for SquirrelFunctions {
sq_pushasset: val.sq_pushasset,
sq_pushvector: val.sq_pushvector,
sq_pushobject: val.sq_pushobject,
sq_pushnull: val.sq_pushnull,
sq_getstring: val.sq_getstring,
sq_getinteger: val.sq_getinteger,
sq_getfloat: val.sq_getfloat,
Expand Down
75 changes: 22 additions & 53 deletions src/high/engine_sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,13 @@ use crate::{
squirreldatatypes::{HSquirrelVM, SQObject},
squirrelfunctions::SquirrelFunctions,
},
high::squirrel_traits::PushToSquirrelVm,
mid::{
squirrel::{SQFUNCTIONS, SQVM_CLIENT, SQVM_SERVER, SQVM_UI},
utils::to_cstring,
},
};

use super::engine::EngineToken;
use super::{engine::EngineToken, squirrel_traits::IntoSquirrelArgs};

static ENGINE_MESSAGE_SEND: OnceCell<Sender<AsyncEngineMessage>> = OnceCell::new();
static ENGINE_MESSAGE_RECV: OnceCell<Mutex<Receiver<AsyncEngineMessage>>> = OnceCell::new();
Expand Down Expand Up @@ -50,7 +49,7 @@ impl AsyncEngineMessage {
pub fn run_squirrel_func(
name: impl Into<String>,
context: ScriptContext,
args: impl IntoSquirrelArgs,
args: impl IntoSquirrelArgs + 'static,
) -> Self {
Self::ExecuteSquirrel {
function_name: name.into(),
Expand Down Expand Up @@ -98,7 +97,6 @@ pub unsafe fn run_async_routine() {
function_name,
args,
} => {
// TODO: when done with sqvm global add it here
let (sqvm, sqfunctions) = match context {
ScriptContext::SERVER => {
(SQVM_SERVER.get(token).borrow(), SQFUNCTIONS.server.wait())
Expand Down Expand Up @@ -126,7 +124,7 @@ pub unsafe fn run_async_routine() {
};

if result != 0 {
log::warn!("async squirrel function failed to executel; it may not be global");
log::warn!("async squirrel function failed to execute; it may not be global");
} else {
unsafe {
let amount = args(sqvm, sqfunctions);
Expand All @@ -147,52 +145,23 @@ pub unsafe fn run_async_routine() {
}
}

// TODO: move this to the squirrel_traits.rs module and rewrite squirrel functions to use a more static aproach with this
// so the trait will handle pushing a whole function signuture into the vm via a struct that requires it's generic to implement this trait :)

/// closure that simplies pushing groups of items to the squirrel vm; asynchronously or immediately
pub trait IntoSquirrelArgs {
/// converts a implemenator of this trait into a closure that pushes it to the squirrel stack when ran
fn into_function(
self,
) -> Box<dyn FnOnce(*mut HSquirrelVM, &'static SquirrelFunctions) -> i32 + 'static + Send + Sync>;
}

// TODO: format this
// TODO: check for correctness
macro_rules! into_squirrel_args_impl{
( $( ($($ty_name: ident : $tuple_index:tt),*) );*; ) => { $(
impl<$($ty_name: PushToSquirrelVm + 'static + Send + Sync,)*> IntoSquirrelArgs for ($($ty_name,)*) {
fn into_function(
self
) -> Box<dyn FnOnce(*mut HSquirrelVM, &'static SquirrelFunctions) -> i32 + 'static + Send + Sync> {
Box::new(move |sqvm: *mut HSquirrelVM, sqfunctions: &'static SquirrelFunctions| { _ =
$(
self.$tuple_index.push_to_sqvm(sqvm, sqfunctions);
)*

$crate::macros::sq_utils::__arg_count_helper([$($crate::__replace_expr!($ty_name)),*]) as i32
})
}
}
)* }
}

// TODO: add single parameter

into_squirrel_args_impl! {
(T1: 0);
(T1: 0, T2: 1);
(T1: 0, T2: 1, T3: 2);
(T1: 0, T2: 1, T3: 2, T4: 3);
(T1: 0, T2: 1, T3: 2, T4: 3, T5: 4);
(T1: 0, T2: 1, T3: 2, T4: 3, T5: 4, T6: 5);
(T1: 0, T2: 1, T3: 2, T4: 3, T5: 4, T6: 5, T7: 6);
(T1: 0, T2: 1, T3: 2, T4: 3, T5: 4, T6: 5, T7: 6, T8: 7);
(T1: 0, T2: 1, T3: 2, T4: 3, T5: 4, T6: 5, T7: 6, T8: 7, T9: 8);
(T1: 0, T2: 1, T3: 2, T4: 3, T5: 4, T6: 5, T7: 6, T8: 7, T9: 8, T10: 9);
}

// TODO: test it
// maybe the test should better than this
#[test]
const fn test_async_engine() {}
fn test_async_engine() {
init_async_routine();

async_execute(AsyncEngineMessage::run_squirrel_func(
"test",
ScriptContext::SERVER,
"test",
))
.unwrap();
async_execute(AsyncEngineMessage::run_func(|_| ())).unwrap();

assert_eq!(
&(0..10)
.filter_map(|_| ENGINE_MESSAGE_RECV.wait().lock().try_recv().ok())
.count(),
&2
);
}
55 changes: 54 additions & 1 deletion src/high/squirrel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
use parking_lot::Mutex;
use std::marker::PhantomData;

use super::{squirrel_traits::IsSQObject, UnsafeHandle};
use super::{
squirrel_traits::{IntoSquirrelArgs, IsSQObject},
UnsafeHandle,
};
use crate::{
bindings::{
squirrelclasstypes::{CompileBufferState, SQRESULT},
Expand Down Expand Up @@ -166,6 +169,54 @@ impl SQHandle<SQClosure> {
}
}

/// provides invariance for calling squirrel functions with little overhead
pub struct SquirrelFn<T: IntoSquirrelArgs> {
pub(crate) func: SQHandle<SQClosure>,
pub(crate) phantom: PhantomData<*mut T>,
}

impl<T: IntoSquirrelArgs> SquirrelFn<T> {
/// calls the underlying squirrel function on the provided sqvm
///
/// # Errors
///
/// This function will return an error if the fails to execute for some reason which is unlikely since it would be type checked
pub fn run(
&mut self,
sqvm: *mut HSquirrelVM,
sqfunctions: &'static SquirrelFunctions,
args: T,
) -> Result<(), CallError> {
unsafe {
let amount = args.into_push(sqvm, sqfunctions);

(sqfunctions.sq_pushobject)(sqvm, self.func.as_callable());
(sqfunctions.sq_pushroottable)(sqvm);

if (sqfunctions.sq_call)(sqvm, amount, true as u32, true as u32)
== SQRESULT::SQRESULT_ERROR
{
return Err(CallError::FunctionFailedToExecute);
}
}
Ok(())
}

/// calls the underlying squirrel function on the provided sqvm
///
/// # Errors
///
/// This function will return an error if the fails to execute for some reason which is unlikely since it would be type checked
pub fn call(
&mut self,
sqvm: *mut HSquirrelVM,
sqfunctions: &'static SquirrelFunctions,
args: T,
) -> Result<(), CallError> {
self.run(sqvm, sqfunctions, args)
}
}

/// Adds a sqfunction to the registration list
///
/// The sqfunction will be registered when its vm is loaded
Expand All @@ -187,6 +238,8 @@ pub fn register_sq_functions(get_info_func: FuncSQFuncInfo) {
FUNCTION_SQ_REGISTER.lock().push(get_info_func());
}

// TODO: use IntoSquirrelArgs here

/// calls any function defined on the sqvm
///
/// this should only be called on the tf2 thread aka when concommands, convars, sqfunctions, runframe
Expand Down
Loading

0 comments on commit f4a5796

Please sign in to comment.