use crate::*;
use paste::paste;
macro_rules! impl_ray_function {
([$n:literal], $($arg:ident: $argp:ident [$argty:ty]),*) => {
paste! {
pub struct [<RayFunction $n>]<$($argp,)* R> {
raw_fn: fn($($argty),*) -> R,
wrapped_fn: InvokerFunction,
ffi_lookup_name: CString,
}
impl<$($argp: serde::Serialize,)* R> [<RayFunction $n>]<$($argp,)* R> {
pub fn new(
raw_fn: fn($($argty),*) -> R,
wrapped_fn: InvokerFunction,
ffi_lookup_name: CString
) -> Self {
Self { raw_fn, wrapped_fn, ffi_lookup_name }
}
pub fn name<'a>(&'a self) -> &'a str {
&self.ffi_lookup_name.to_str().unwrap()
}
pub fn call(&self, $($arg: $argty),*) -> R {
(self.raw_fn)($($arg),*)
}
pub fn remote<$([<$argp Borrow>]: std::borrow::Borrow<$argp>),*>(
&self,
$($arg: [<$argp Borrow>]),*
) -> CString
{
let mut task_args = Vec::new();
$(
let result = rmp_serde::to_vec($arg.borrow()).unwrap();
task_args.push(result);
)*
ray_rs_sys::internal::submit(self.ffi_lookup_name.clone(), &mut task_args)
}
pub fn ray_call(&self, args: RustBuffer) -> RustBuffer {
(self.wrapped_fn)(args)
}
pub fn get_invoker(&self) -> InvokerFunction {
self.wrapped_fn
}
}
impl<$($argp,)* R> std::ops::FnOnce<($($argty),*)> for [<RayFunction $n>]<$($argp,)* R> {
type Output = R;
extern "rust-call" fn call_once(self, ($($arg),*): ($($argty),*)) -> Self::Output {
(self.raw_fn)($($arg),*)
}
}
impl<$($argp,)* R> std::ops::FnMut<($($argty),*)> for [<RayFunction $n>]<$($argp,)* R> {
extern "rust-call" fn call_mut(&mut self, ($($arg),*): ($($argty),*)) -> Self::Output {
(self.raw_fn)($($arg),*)
}
}
impl<$($argp,)* R> std::ops::Fn<($($argty),*)> for [<RayFunction $n>]<$($argp,)* R> {
extern "rust-call" fn call(&self, ($($arg),*): ($($argty),*)) -> Self::Output {
(self.raw_fn)($($arg),*)
}
}
}
};
}
impl_ray_function!([0], );
impl_ray_function!([1], a0: T0 [T0]);
impl_ray_function!([2], a0: T0 [T0], a1: T1 [T1]);
impl_ray_function!([3], a0: T0 [T0], a1: T1 [T1], a2: T2 [T2]);
#[macro_export]
macro_rules! count {
() => (0usize);
( $x:tt $($xs:tt)* ) => (1usize + count!($($xs)*));
}
#[macro_export]
macro_rules! deserialize {
($ptrs:ident, $sizes:ident) => {};
($ptrs:ident, $sizes:ident, $arg:ident: $argty:ty $(,$args:ident: $argsty:ty)*) => {
deserialize!($ptrs, $sizes $(,$args:$argsty)*);
let ptr = $ptrs[$ptrs.len() - count!($($args)*) - 1];
let size = $sizes[$sizes.len() - count!($($args)*) - 1];
let $arg = rmp_serde::from_read_ref::<_, $argty>(
unsafe { std::slice::from_raw_parts(ptr as *const u8, size as usize) }
).unwrap();
};
}
#[macro_export]
macro_rules! serialize {
($ptrs:ident) => {};
($ptrs:ident, $arg:ident: $argty:ty $(,$args:ident: $argsty:ty)*) => {
serialize!($ptrs $(,$args:$argsty)*);
let (ptr, size) = $ptrs[$ptrs.len() - count!($($args)*) - 1];
let $arg = rmp_serde::from_read_ref::<_, $argty>(
unsafe { std::slice::from_raw_parts(ptr as *const u8, size as usize) }
).unwrap();
};
}
#[macro_export]
macro_rules! remote_internal {
($lit_n:literal, $name:ident ($($arg:ident: $argty:ty),*) -> $ret:ty $body:block) => {
paste! {
fn [<ray_rust_private_ $name>]($($arg: $argty,)*) -> $ret {
$body
}
#[no_mangle]
pub extern "C" fn [<ray_rust_ffi_ $name>](args: RustBuffer) -> RustBuffer {
let (arg_raw_ptrs, sizes) = rmp_serde::from_read_ref::<_, (Vec<u64>, Vec<u64>)>(
&args.destroy_into_vec()
).unwrap();
deserialize!(arg_raw_ptrs, sizes $(,$arg:$argty)*);
let ret: $ret = [<ray_rust_private_ $name>]($($arg,)*);
let result = rmp_serde::to_vec(&ret).unwrap();
RustBuffer::from_vec(result)
}
#[allow(non_upper_case_globals)]
lazy_static! {
pub static ref $name: [<RayFunction $lit_n>]<$($argty,)* $ret>
= [<RayFunction $lit_n>]::new(
[<ray_rust_private_ $name>],
[<ray_rust_ffi_ $name>],
CString::new(
stringify!([<ray_rust_ffi_ $name>])).unwrap()
);
}
}
};
}
#[macro_export]
macro_rules! match_remote {
([$name:ident ($($arg:ident: $argty:ty),*) -> $ret:ty $body:block]) => { remote_internal!(0, $name ($($arg: $argty),*) -> $ret $body); };
($x:tt [$name:ident ($($arg:ident: $argty:ty),*) -> $ret:ty $body:block]) => { remote_internal!(1, $name ($($arg: $argty),*) -> $ret $body); };
($x:tt $y:tt [$name:ident ($($arg:ident: $argty:ty),*) -> $ret:ty $body:block]) => { remote_internal!(2, $name ($($arg: $argty),*) -> $ret $body); };
($x:tt $y:tt $z:tt [$name:ident ($($arg:ident: $argty:ty),*) -> $ret:ty $body:block]) => { remote_internal!(3, $name ($($arg: $argty),*) -> $ret $body); };
}
#[macro_export]
macro_rules! remote {
(pub fn $name:ident ($($arg:ident: $argty:ty),*) -> $ret:ty $body:block) => {
match_remote!($($arg)* [$name ($($arg: $argty),*) -> $ret $body]);
}
}
pub fn get<R: serde::de::DeserializeOwned>(id : CString) -> R {
let buf = ray_rs_sys::internal::get_slice(id, -1);
rmp_serde::from_read_ref::<_, R>(buf).unwrap()
}