use crate::error::*;
use crate::marker::*;
use crate::maybe_future::*;
use crate::types::*;
use crate::values::*;
use std::sync::Arc;
pub mod decl;
pub use decl::*;
pub mod overload;
pub use overload::*;
mod registry;
pub use registry::*;
mod bindings;
pub use bindings::*;
pub trait Arguments: Sized + private::Sealed {
const LEN: usize;
}
pub trait NonEmptyArguments: Arguments + private::Sealed {}
pub trait IntoFunction<'f, Fm: FnMarker, Args = ()>: private::Sealed<Fm, Args> {
fn into_function(self) -> Function<'f>;
}
#[derive(Debug, Clone)]
pub struct Function<'f> {
inner: Arc<dyn ErasedFn + 'f>,
}
impl<'f> Function<'f> {
fn new(inner: impl ErasedFn + 'f) -> Self {
Self {
inner: Arc::new(inner),
}
}
pub fn call<'this, 'future>(&'this self, args: Vec<Value>) -> MaybeFuture<'future, Value, Error>
where
'this: 'future,
Self: 'future,
{
self.inner.call(args)
}
pub fn arguments(&self) -> Vec<ValueType> {
self.inner.arguments()
}
pub fn result(&self) -> ValueType {
self.inner.result()
}
pub fn function_type(&self) -> FunctionType {
FunctionType::new(self.result(), self.arguments())
}
pub fn arguments_len(&self) -> usize {
self.inner.arguments_len()
}
}
trait ErasedFn: Send + Sync {
fn call<'this, 'future>(&'this self, args: Vec<Value>) -> MaybeFuture<'future, Value, Error>
where
'this: 'future,
Self: 'future;
fn arguments(&self) -> Vec<ValueType>;
fn result(&self) -> ValueType;
fn arguments_len(&self) -> usize;
}
macro_rules! impl_arguments {
() => {
impl Arguments for () {
const LEN: usize = 0;
}
impl private::Sealed for () {}
};
(
$($ty:ident),+
) => {
impl<$($ty: FromValue + TypedValue),+> Arguments for ($($ty,)*) {
const LEN: usize = count_args!($($ty),*) as usize;
}
impl<$($ty: FromValue + TypedValue),+> NonEmptyArguments for ($($ty,)*) {}
impl<$($ty: FromValue + TypedValue),+> private::Sealed for ($($ty,)*) {}
}
}
impl_arguments!();
impl_arguments!(A1);
impl_arguments!(A1, A2);
impl_arguments!(A1, A2, A3);
impl_arguments!(A1, A2, A3, A4);
impl_arguments!(A1, A2, A3, A4, A5);
impl_arguments!(A1, A2, A3, A4, A5, A6);
impl_arguments!(A1, A2, A3, A4, A5, A6, A7);
impl_arguments!(A1, A2, A3, A4, A5, A6, A7, A8);
impl_arguments!(A1, A2, A3, A4, A5, A6, A7, A8, A9);
impl_arguments!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
trait Argument: FromValue + TypedValue {
fn make_argument(value: &Value) -> Result<Self, FromValueError> {
let output = <Self as FromValue>::from_value(value)?;
Ok(unsafe { Self::from_output(output) })
}
unsafe fn from_output<'a>(output: <Self as FromValue>::Output<'a>) -> Self {
debug_assert!(
std::mem::size_of::<<Self as FromValue>::Output<'a>>() == std::mem::size_of::<Self>()
);
let ptr: *const Self = (&output as *const <Self as FromValue>::Output<'a>).cast();
std::mem::forget(output);
std::ptr::read(ptr)
}
}
impl<T: FromValue + TypedValue> Argument for T {}
struct FnWrapper<F, R, Args> {
func: F,
_phantom: std::marker::PhantomData<(R, Args)>,
}
impl<F, R, Args> FnWrapper<F, R, Args> {
fn new(func: F) -> Self {
Self {
func,
_phantom: std::marker::PhantomData,
}
}
}
macro_rules! count_args {
() => { 0 };
($head:ident $(, $tail:ident)*) => { 1 + count_args!($($tail),*) };
}
use count_args;
macro_rules! impl_fn_wrapper {
($($ty:ident),*) => {
paste::paste! {
impl<F, R, $($ty,)*> ErasedFn for FnWrapper<F, R, ($($ty,)*)>
where
F: Fn($($ty,)*) -> R + Send + Sync,
R: IntoResult + Send + Sync,
$($ty: FromValue + TypedValue + Send + Sync,)*
{
fn call<'this, 'future>(
&'this self,
args: Vec<Value>
) -> MaybeFuture<'future, Value, Error>
where 'this: 'future, Self: 'future {
let f = || {
const EXPECTED_LEN: usize = count_args!($($ty),*);
if args.len() != EXPECTED_LEN {
return Err(Error::invalid_argument(
format!("expected {} arguments, got {}", EXPECTED_LEN, args.len())
));
}
#[allow(unused_mut, unused_variables)]
let mut iter = args.iter();
$(
let [< $ty:lower >] = $ty::make_argument(
iter.next().expect("argument count already validated")
).map_err(|e| Error::invalid_argument(format!("argument error: {}", e)))?;
)*
let result = (self.func)($([< $ty:lower >],)*);
result.into_result()
};
f().into()
}
fn arguments(&self) -> Vec<ValueType> {
vec![$($ty::value_type()),*]
}
fn result(&self) -> ValueType {
R::value_type()
}
fn arguments_len(&self) -> usize {
count_args!($($ty),*)
}
}
impl<'f, F, R, $($ty,)*> IntoFunction<'f, (), ($($ty,)*)> for F
where
F: Fn($($ty,)*) -> R + Send + Sync + 'f,
R: IntoResult + Send + Sync + 'f,
($($ty,)*): Arguments,
$($ty: FromValue + TypedValue + Send + Sync + 'f,)*
{
fn into_function(self) -> Function<'f> {
Function::new(FnWrapper::<F, R, ($($ty,)*)>::new(self))
}
}
impl<'f, F, R, $($ty,)*> private::Sealed<(), ($($ty,)*)> for F
where
F: Fn($($ty,)*) -> R + Send + Sync + 'f,
R: IntoResult + Send + Sync + 'f,
($($ty,)*): Arguments,
$($ty: FromValue + TypedValue + Send + Sync + 'f,)*
{}
}
};
}
impl_fn_wrapper!();
impl_fn_wrapper!(A1);
impl_fn_wrapper!(A1, A2);
impl_fn_wrapper!(A1, A2, A3);
impl_fn_wrapper!(A1, A2, A3, A4);
impl_fn_wrapper!(A1, A2, A3, A4, A5);
impl_fn_wrapper!(A1, A2, A3, A4, A5, A6);
impl_fn_wrapper!(A1, A2, A3, A4, A5, A6, A7);
impl_fn_wrapper!(A1, A2, A3, A4, A5, A6, A7, A8);
impl_fn_wrapper!(A1, A2, A3, A4, A5, A6, A7, A8, A9);
impl_fn_wrapper!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
struct FnWrapperAsync<F, R, Args> {
func: F,
_phantom: std::marker::PhantomData<(R, Args)>,
}
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
impl<F, R, Args> FnWrapperAsync<F, R, Args> {
fn new(func: F) -> Self {
Self {
func,
_phantom: std::marker::PhantomData,
}
}
}
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
mod async_impls {
use super::*;
macro_rules! impl_fn_wrapper_async {
($($ty:ident),*) => {
paste::paste! {
impl<F, Fut, R, $($ty,)*> ErasedFn for FnWrapperAsync<F, R, ($($ty,)*)>
where
F: Fn($($ty,)*) -> Fut + Send + Sync,
Fut: std::future::Future<Output = R> + Send,
R: IntoResult + Send + Sync,
$($ty: FromValue + TypedValue + Send + Sync,)*
{
fn call<'this, 'future>(
&'this self,
args: Vec<Value>
) -> MaybeFuture<'future, Value, Error>
where 'this: 'future, Self: 'future {
let f = || async move {
const EXPECTED_LEN: usize = count_args!($($ty),*);
if args.len() != EXPECTED_LEN {
return Err(Error::invalid_argument(
format!("expected {} arguments, got {}", EXPECTED_LEN, args.len())
));
}
#[allow(unused_mut, unused_variables)]
let mut iter = args.iter();
$(
let [< $ty:lower >] = $ty::make_argument(
iter.next().expect("argument count already validated")
).map_err(|e| Error::invalid_argument(format!("argument error: {}", e)))?;
)*
let future = (self.func)($([< $ty:lower >],)*);
let result = future.await;
result.into_result()
};
Box::pin(f()).into()
}
fn arguments(&self) -> Vec<ValueType> {
vec![$($ty::value_type()),*]
}
fn result(&self) -> ValueType {
R::value_type()
}
fn arguments_len(&self) -> usize {
count_args!($($ty),*)
}
}
impl<'f, F, Fut, R, $($ty,)*> IntoFunction<'f, Async, ($($ty,)*)> for F
where
F: Fn($($ty,)*) -> Fut + Send + Sync + 'f,
Fut: std::future::Future<Output = R> + Send + 'f,
R: IntoResult + Send + Sync + 'f,
$($ty: FromValue + TypedValue + Send + Sync + 'f,)*
{
fn into_function(self) -> Function<'f> {
Function::new(FnWrapperAsync::<F, R, ($($ty,)*)>::new(self))
}
}
impl<'f, F, Fut, R, $($ty,)*> private::Sealed<Async, ($($ty,)*)> for F
where
F: Fn($($ty,)*) -> Fut + Send + Sync + 'f,
Fut: std::future::Future<Output = R> + Send + 'f,
R: IntoResult + Send + Sync + 'f,
$($ty: FromValue + TypedValue + Send + Sync + 'f,)*
{}
}
};
}
impl_fn_wrapper_async!();
impl_fn_wrapper_async!(A1);
impl_fn_wrapper_async!(A1, A2);
impl_fn_wrapper_async!(A1, A2, A3);
impl_fn_wrapper_async!(A1, A2, A3, A4);
impl_fn_wrapper_async!(A1, A2, A3, A4, A5);
impl_fn_wrapper_async!(A1, A2, A3, A4, A5, A6);
impl_fn_wrapper_async!(A1, A2, A3, A4, A5, A6, A7);
impl_fn_wrapper_async!(A1, A2, A3, A4, A5, A6, A7, A8);
impl_fn_wrapper_async!(A1, A2, A3, A4, A5, A6, A7, A8, A9);
impl_fn_wrapper_async!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
}
impl std::fmt::Debug for dyn ErasedFn + '_ {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("<function>")
}
}
mod private {
#[derive(Debug)]
pub enum Placeholder {}
pub trait Sealed<T = Placeholder, U = Placeholder> {}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic_function_registration() {
fn add(a: i64, b: i64) -> i64 {
a + b
}
let func = add.into_function();
assert_eq!(func.arguments(), vec![ValueType::Int, ValueType::Int]);
assert_eq!(func.result(), ValueType::Int);
let multiplier = 3;
let multiply = move |x: i64| -> i64 { x * multiplier };
let func2 = multiply.into_function();
assert_eq!(func2.arguments(), vec![ValueType::Int]);
assert_eq!(func2.result(), ValueType::Int);
}
#[test]
fn test_reference_return_functions() {
fn return_arg(a: &str) -> &str {
a
}
let func = return_arg.into_function();
assert_eq!(func.arguments(), vec![ValueType::String]);
assert_eq!(func.result(), ValueType::String);
let result = func.call(vec!["hello".into()]);
#[cfg(feature = "async")]
let result = result.expect_result("test_reference_return_functions");
assert_eq!(result.unwrap(), "hello".into());
}
#[test]
fn test_closure_with_captured_data() {
let prefix = String::from("Hello, ");
let with_prefix = move |name: &str| -> String { format!("{prefix}{name}") };
let func = with_prefix.into_function();
assert_eq!(func.arguments(), vec![ValueType::String]);
assert_eq!(func.result(), ValueType::String);
let result = func.call(vec!["world".into()]);
#[cfg(feature = "async")]
let result = result.expect_result("test_closure_with_captured_data");
assert_eq!(result.unwrap(), "Hello, world".into());
}
#[test]
fn test_zero_parameter_function() {
fn get_answer() -> i64 {
42
}
let func = get_answer.into_function();
assert_eq!(func.arguments(), vec![]);
assert_eq!(func.result(), ValueType::Int);
let result = func.call(vec![]);
#[cfg(feature = "async")]
let result = result.expect_result("test_zero_parameter_function");
assert_eq!(result.unwrap(), 42i64.into());
}
#[test]
fn test_multiple_parameter_function() {
fn add_three(a: i64, b: i64, c: i64) -> i64 {
a + b + c
}
let func = add_three.into_function();
assert_eq!(
func.arguments(),
vec![ValueType::Int, ValueType::Int, ValueType::Int]
);
assert_eq!(func.result(), ValueType::Int);
let result = func.call(vec![1i64.into(), 2i64.into(), 3i64.into()]);
#[cfg(feature = "async")]
let result = result.expect_result("test_multiple_parameter_function");
assert_eq!(result.unwrap(), 6i64.into());
}
#[test]
fn test_result_error_handling() {
fn divide(a: i64, b: i64) -> Result<i64, std::io::Error> {
if b == 0 {
Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"division by zero",
))
} else {
Ok(a / b)
}
}
let func = divide.into_function();
assert_eq!(func.arguments(), vec![ValueType::Int, ValueType::Int]);
assert_eq!(func.result(), ValueType::Int);
let result = func.call(vec![10i64.into(), 2i64.into()]);
#[cfg(feature = "async")]
let result = result.expect_result("test_result_error_handling_success");
assert_eq!(result.unwrap(), 5i64.into());
let result = func.call(vec![10i64.into(), 0i64.into()]);
#[cfg(feature = "async")]
let result = result.expect_result("test_result_error_handling_error");
assert!(result.is_err());
}
}