#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! count_args {
() => { 0 };
($name:ident) => { 1 };
($first:ident, $($rest:ident),*) => {
1 + count_args!($($rest),*)
}
}
macro_rules! invoke_fn_impl {
($(
fn $FnName:ident($($Arg:tt: $T:ident),*) -> $ErrName:ident;
)+) => {
$(
pub struct $ErrName<'s, $($T: ArgumentReflection,)* Output: ReturnTypeReflection> {
msg: String,
runtime: std::rc::Rc<core::cell::RefCell<Runtime>>,
function_name: &'s str,
$($Arg: $T,)*
output: core::marker::PhantomData<Output>,
}
impl<'s, $($T: ArgumentReflection,)* Output: ReturnTypeReflection> core::fmt::Debug for $ErrName<'s, $($T,)* Output> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", &self.msg)
}
}
impl<'s, $($T: ArgumentReflection,)* Output: ReturnTypeReflection> core::fmt::Display for $ErrName<'s, $($T,)* Output> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", &self.msg)
}
}
impl<'s, $($T: ArgumentReflection,)* Output: ReturnTypeReflection> std::error::Error for $ErrName<'s, $($T,)* Output> {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
}
impl<'s, $($T: ArgumentReflection,)* Output: ReturnTypeReflection> $ErrName<'s, $($T,)* Output> {
#[allow(clippy::too_many_arguments)]
pub fn new(err_msg: String, runtime: std::rc::Rc<core::cell::RefCell<Runtime>>, function_name: &'s str, $($Arg: $T),*) -> Self {
Self {
msg: err_msg,
runtime,
function_name,
$($Arg,)*
output: core::marker::PhantomData,
}
}
}
impl<'s, $($T: ArgumentReflection,)* Output: ReturnTypeReflection> $crate::RetryResultExt for core::result::Result<Output, $ErrName<'s, $($T,)* Output>> {
type Output = Output;
fn retry(self) -> Self {
match self {
Ok(output) => Ok(output),
Err(err) => {
eprintln!("{}", err.msg);
while !err.runtime.borrow_mut().update() {
}
$crate::Runtime::$FnName(&err.runtime, err.function_name, $(err.$Arg,)*)
}
}
}
fn wait(mut self) -> Self::Output {
loop {
if let Ok(output) = self {
return output;
} else {
self = self.retry();
}
}
}
}
impl Runtime {
#[allow(clippy::too_many_arguments, unused_assignments)]
pub fn $FnName<'s, $($T: ArgumentReflection,)* Output: ReturnTypeReflection>(
runtime: &std::rc::Rc<core::cell::RefCell<Runtime>>,
function_name: &'s str,
$($Arg: $T,)*
) -> core::result::Result<Output, $ErrName<'s, $($T,)* Output>> {
let runtime_ref = runtime.borrow();
match runtime_ref
.get_function_definition(function_name)
.ok_or_else(|| format!("Failed to obtain function '{}'", function_name))
.and_then(|function_info| {
let num_args = $crate::count_args!($($T),*);
let arg_types = function_info.prototype.signature.arg_types();
if arg_types.len() != num_args {
return Err(format!(
"Invalid number of arguments. Expected: {}. Found: {}.",
arg_types.len(),
num_args,
));
}
#[allow(unused_mut, unused_variables)]
let mut idx = 0;
$(
crate::reflection::equals_argument_type(&runtime_ref, &arg_types[idx], &$Arg)
.map_err(|(expected, found)| {
format!(
"Invalid argument type at index {}. Expected: {}. Found: {}.",
idx,
expected,
found,
)
})?;
idx += 1;
)*
if let Some(return_type) = function_info.prototype.signature.return_type() {
crate::reflection::equals_return_type::<Output>(return_type)
} else if <() as ReturnTypeReflection>::type_guid() != Output::type_guid() {
Err((<() as ReturnTypeReflection>::type_name(), Output::type_name()))
} else {
Ok(())
}.map_err(|(expected, found)| {
format!(
"Invalid return type. Expected: {}. Found: {}",
expected,
found,
)
})?;
Ok(function_info)
}) {
Ok(function_info) => {
let function: fn($($T::Marshalled),*) -> Output::Marshalled = unsafe {
core::mem::transmute(function_info.fn_ptr)
};
let result = function($($Arg.marshal()),*);
return Ok(result.marshal_value(runtime.clone()))
}
Err(e) => Err($ErrName::new(e, runtime.clone(), function_name, $($Arg),*))
}
}
}
)+
}
}
#[macro_export]
macro_rules! invoke_fn {
($Runtime:expr, $FnName:expr) => {
$crate::Runtime::invoke_fn0(&$Runtime, $FnName)
};
($Runtime:expr, $FnName:expr, $A:expr) => {
$crate::Runtime::invoke_fn1(&$Runtime, $FnName, $A)
};
($Runtime:expr, $FnName:expr, $A:expr, $B:expr) => {
$crate::Runtime::invoke_fn2(&$Runtime, $FnName, $A, $B)
};
($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr) => {
$crate::Runtime::invoke_fn3(&$Runtime, $FnName, $A, $B, $C)
};
($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr, $D:expr) => {
$crate::Runtime::invoke_fn4(&$Runtime, $FnName, $A, $B, $C, $D)
};
($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr, $D:expr, $E:expr) => {
$crate::Runtime::invoke_fn5(&$Runtime, $FnName, $A, $B, $C, $D, $E)
};
($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr, $D:expr, $E:expr, $F:expr) => {
$crate::Runtime::invoke_fn6(&$Runtime, $FnName, $A, $B, $C, $D, $E, $F)
};
($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr, $D:expr, $E:expr, $F:expr, $G:expr) => {
$crate::Runtime::invoke_fn7(&$Runtime, $FnName, $A, $B, $C, $D, $E, $F, $G)
};
($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr, $D:expr, $E:expr, $F:expr, $G:expr, $H:expr) => {
$crate::Runtime::invoke_fn8(&$Runtime, $FnName, $A, $B, $C, $D, $E, $F, $G, $H)
};
($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr, $D:expr, $E:expr, $F:expr, $G:expr, $H:expr, $I:expr) => {
$crate::Runtime::invoke_fn9(&$Runtime, $FnName, $A, $B, $C, $D, $E, $F, $G, $H, $I)
};
($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr, $D:expr, $E:expr, $F:expr, $G:expr, $H:expr, $I:expr, $J:expr) => {
$crate::Runtime::invoke_fn10(&$Runtime, $FnName, $A, $B, $C, $D, $E, $F, $G, $H, $I, $J)
};
($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr, $D:expr, $E:expr, $F:expr, $G:expr, $H:expr, $I:expr, $J:expr, $K:expr) => {
$crate::Runtime::invoke_fn11(
&$Runtime, $FnName, $A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K,
)
};
($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr, $D:expr, $E:expr, $F:expr, $G:expr, $H:expr, $I:expr, $J:expr, $K:expr, $L:expr) => {
$crate::Runtime::invoke_fn12(
&$Runtime, $FnName, $A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K, $L,
)
};
($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr, $D:expr, $E:expr, $F:expr, $G:expr, $H:expr, $I:expr, $J:expr, $K:expr, $L:expr, $M:expr) => {
$crate::Runtime::invoke_fn13(
&$Runtime, $FnName, $A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K, $L, $M,
)
};
($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr, $D:expr, $E:expr, $F:expr, $G:expr, $H:expr, $I:expr, $J:expr, $K:expr, $L:expr, $M:expr, $N:expr) => {
$crate::Runtime::invoke_fn14(
&$Runtime, $FnName, $A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K, $L, $M, $N,
)
};
($Runtime:expr, $FnName:expr, $A:expr, $B:expr, $C:expr, $D:expr, $E:expr, $F:expr, $G:expr, $H:expr, $I:expr, $J:expr, $K:expr, $L:expr, $M:expr, $N:expr, $O:expr) => {
$crate::Runtime::invoke_fn15(
&$Runtime, $FnName, $A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K, $L, $M, $N, $O,
)
};
}