#[macro_export]
macro_rules! callback {
($name:ident($($param:ident: $ty:ty),*)) => {
callback!($name($($param: $ty),*) -> ());
};
($name:ident($($param:ident: $ty:ty),*) -> $rval:ty $(, namespace = $ns:expr)?) => {
#[derive(Default)]
#[repr(C)]
pub struct $name {
/// The function pointer to invoke. `None` means the callback is absent.
pub callback: ::std::option::Option<extern "C" fn($($ty,)* *const ::std::ffi::c_void) -> $rval>,
pub data: *const ::std::ffi::c_void,
pub destructor: ::std::option::Option<unsafe extern "C" fn(*const ::std::ffi::c_void)>,
}
unsafe impl ::std::marker::Send for $name {}
unsafe impl ::std::marker::Sync for $name {}
impl ::std::ops::Drop for $name {
fn drop(&mut self) {
if let Some(dtor) = self.destructor {
unsafe { dtor(self.data) };
}
}
}
impl $name {
pub fn from_fn<F>(f: F) -> Self
where
F: Fn($($ty),*) -> $rval + Send + Sync + 'static,
{
extern "C" fn trampoline<F: Fn($($ty),*) -> $rval>(
$($param: $ty,)*
ctx: *const ::std::ffi::c_void,
) -> $rval {
let f = unsafe { &*(ctx as *const F) };
f($($param,)*)
}
unsafe extern "C" fn destructor<F>(ctx: *const ::std::ffi::c_void) {
drop(unsafe { ::std::boxed::Box::from_raw(ctx as *mut F) });
}
let ptr = ::std::boxed::Box::into_raw(::std::boxed::Box::new(f)) as *const ::std::ffi::c_void;
Self { callback: Some(trampoline::<F>), data: ptr, destructor: Some(destructor::<F>) }
}
pub fn call(&self, $($param: $ty),*) -> $rval {
self.callback.expect("Assumed function would exist but it didn't.")($($param,)* self.data)
}
pub fn call_if_some(&self, $($param: $ty,)*) -> ::std::option::Option<$rval> {
match self.callback {
Some(c) => Some(c($($param,)* self.data)),
None => None
}
}
}
impl From<for<> extern "C" fn($($ty,)* *const ::std::ffi::c_void) -> $rval> for $name {
fn from(x: extern "C" fn($($ty,)* *const ::std::ffi::c_void) -> $rval) -> Self {
Self { callback: Some(x), data: ::std::ptr::null(), destructor: None }
}
}
impl From<$name> for ::std::option::Option<extern "C" fn($($ty,)* *const ::std::ffi::c_void) -> $rval> {
fn from(x: $name) -> Self {
x.callback
}
}
unsafe impl $crate::lang::types::TypeInfo for $name {
const WIRE_SAFE: bool = <$rval>::WIRE_SAFE $(&& <$ty>::WIRE_SAFE)*;
const RAW_SAFE: bool = <$rval>::RAW_SAFE $(&& <$ty>::RAW_SAFE)*;
const ASYNC_SAFE: bool = <$rval>::ASYNC_SAFE $(&& <$ty>::ASYNC_SAFE)*;
const SERVICE_SAFE: bool = false;
const SERVICE_CTOR_SAFE: bool = false;
fn id() -> $crate::inventory::TypeId {
$crate::inventory::TypeId::from_id($crate::id!($name))
}
fn kind() -> $crate::lang::types::TypeKind {
let sig = $crate::lang::function::Signature {
arguments: vec![
$($crate::lang::function::Argument::new(stringify!($param), <$ty>::id()),)*
],
rval: <$rval>::id(),
};
$crate::lang::types::TypeKind::TypePattern($crate::lang::types::TypePattern::NamedCallback(sig))
}
fn ty() -> $crate::lang::types::Type {
let r = <$rval>::ty();
$(let $param = <$ty>::ty();)*
let emissision = [
r.emission.clone(),
$($param.emission.clone(),)*
];
let sig = $crate::lang::function::Signature {
arguments: vec![
$($crate::lang::function::Argument::new(stringify!($param), <$ty>::id()),)*
],
rval: <$rval>::id(),
};
$crate::lang::types::Type {
emission: $crate::lang::meta::common_or_module_emission(&emissision),
docs: $crate::lang::meta::Docs::empty(),
visibility: $crate::lang::meta::Visibility::Public,
name: stringify!($name).to_string(),
kind: $crate::lang::types::TypeKind::TypePattern($crate::lang::types::TypePattern::NamedCallback(sig)),
}
}
fn register(inventory: &mut impl $crate::inventory::Inventory) {
<$rval>::register(inventory);
$(<$ty>::register(inventory);)*
<*const ::std::ffi::c_void>::register(inventory);
inventory.register_type(Self::id(), Self::ty());
}
}
unsafe impl $crate::lang::types::WireIO for $name {
fn write(&self, _: &mut impl ::std::io::Write) -> Result<(), $crate::wire::SerializationError> {
$crate::bad_wire!()
}
fn read(_: &mut impl ::std::io::Read) -> Result<Self, $crate::wire::SerializationError> {
$crate::bad_wire!()
}
fn live_size(&self) -> usize {
$crate::bad_wire!()
}
}
};
}