use crate::{core::FfiResult, err, error::Fallible, fallible};
macro_rules! dispatch {
($function:ident, [$($rt_dispatch_types:tt),+], $args:tt) => {
disp!($function, [$($rt_dispatch_types),+], (), $args)
};
($function:ident, [$($rt_dispatch_types:tt),+]) => {
dispatch!($function, [$($rt_dispatch_types),+], ())
};
}
macro_rules! disp {
($function:ident, [$rt_dispatch_types_0:tt, $($rt_dispatch_types_n:tt),+], $type_args:tt, $args:tt) => {
disp_expand!($function, $rt_dispatch_types_0, [$($rt_dispatch_types_n),+], $type_args, $args)
};
($function:ident, [$rt_dispatch_types_0:tt], $type_args:tt, $args:tt) => {
disp_expand!($function, $rt_dispatch_types_0, [], $type_args, $args)
};
($function:ident, [], ($($type_arg:ty),+), ($($arg:expr),*)) => {
$function::<$($type_arg),+>($($arg),*)
};
}
#[cfg(not(debug_assertions))]
macro_rules! disp_expand {
($function:ident, ($rt_type:expr, @primitives), $rt_dispatch_types:tt, $type_args:tt, $args:tt) => {
disp_expand!($function, ($rt_type, [u32, u64, i32, i64, usize, f32, f64, bool, String]), $rt_dispatch_types, $type_args, $args)
};
($function:ident, ($rt_type:expr, @primitives_plus), $rt_dispatch_types:tt, $type_args:tt, $args:tt) => {
disp_expand!($function, ($rt_type, [u32, u64, i32, i64, usize, f32, f64, bool, String, AnyObject, ExtrinsicObject]), $rt_dispatch_types, $type_args, $args)
};
($function:ident, ($rt_type:expr, @numbers), $rt_dispatch_types:tt, $type_args:tt, $args:tt) => {
disp_expand!($function, ($rt_type, [u32, u64, i32, i64, usize, f32, f64]), $rt_dispatch_types, $type_args, $args)
};
($function:ident, ($rt_type:expr, @hashable), $rt_dispatch_types:tt, $type_args:tt, $args:tt) => {
disp_expand!($function, ($rt_type, [u32, u64, i32, i64, usize, bool, String]), $rt_dispatch_types, $type_args, $args)
};
($function:ident, ($rt_type:expr, @floats), $rt_dispatch_types:tt, $type_args:tt, $args:tt) => {
disp_expand!($function, ($rt_type, [f32, f64]), $rt_dispatch_types, $type_args, $args)
};
($function:ident, ($rt_type:expr, @integers), $rt_dispatch_types:tt, $type_args:tt, $args:tt) => {
disp_expand!($function, ($rt_type, [u32, u64, i32, i64, usize]), $rt_dispatch_types, $type_args, $args)
};
($function:ident, ($rt_type:expr, @dataset_metrics), $rt_dispatch_types:tt, $type_args:tt, $args:tt) => {
disp_expand!($function, ($rt_type, [crate::metrics::SymmetricDistance, crate::metrics::InsertDeleteDistance]), $rt_dispatch_types, $type_args, $args)
};
($function:ident, ($rt_type:expr, @multiset_metrics), $rt_dispatch_types:tt, $type_args:tt, $args:tt) => {
disp_expand!($function, ($rt_type, [crate::metrics::SymmetricDistance, crate::metrics::SymmetricIdDistance, crate::metrics::InsertDeleteDistance]), $rt_dispatch_types, $type_args, $args)
};
($function:ident, ($rt_type:expr, [$($dispatch_type:ty),+]), $rt_dispatch_types:tt, $type_args:tt, $args:tt) => {
match $rt_type.id {
$(x if x == std::any::TypeId::of::<$dispatch_type>() => disp_1!($function, $rt_dispatch_types, $type_args, $dispatch_type, $args)),+,
_ => crate::ffi::dispatch::FailedDispatch::failed_dispatch($rt_type.descriptor.as_str())
}
};
}
#[cfg(debug_assertions)]
macro_rules! disp_expand {
($function:ident, ($rt_type:expr, @primitives), $rt_dispatch_types:tt, $type_args:tt, $args:tt) => {
disp_expand!($function, ($rt_type, [u32, i32, f64, usize, bool, String]), $rt_dispatch_types, $type_args, $args)
};
($function:ident, ($rt_type:expr, @primitives_plus), $rt_dispatch_types:tt, $type_args:tt, $args:tt) => {
disp_expand!($function, ($rt_type, [u32, i32, f64, usize, bool, String, AnyObject, ExtrinsicObject]), $rt_dispatch_types, $type_args, $args)
};
($function:ident, ($rt_type:expr, @numbers), $rt_dispatch_types:tt, $type_args:tt, $args:tt) => {
disp_expand!($function, ($rt_type, [u32, i32, f64]), $rt_dispatch_types, $type_args, $args)
};
($function:ident, ($rt_type:expr, @hashable), $rt_dispatch_types:tt, $type_args:tt, $args:tt) => {
disp_expand!($function, ($rt_type, [String]), $rt_dispatch_types, $type_args, $args)
};
($function:ident, ($rt_type:expr, @floats), $rt_dispatch_types:tt, $type_args:tt, $args:tt) => {
disp_expand!($function, ($rt_type, [f64]), $rt_dispatch_types, $type_args, $args)
};
($function:ident, ($rt_type:expr, @integers), $rt_dispatch_types:tt, $type_args:tt, $args:tt) => {
disp_expand!($function, ($rt_type, [i32]), $rt_dispatch_types, $type_args, $args)
};
($function:ident, ($rt_type:expr, @dataset_metrics), $rt_dispatch_types:tt, $type_args:tt, $args:tt) => {
disp_expand!($function, ($rt_type, [crate::metrics::SymmetricDistance]), $rt_dispatch_types, $type_args, $args)
};
($function:ident, ($rt_type:expr, @multiset_metrics), $rt_dispatch_types:tt, $type_args:tt, $args:tt) => {
disp_expand!($function, ($rt_type, [crate::metrics::SymmetricDistance, crate::metrics::SymmetricIdDistance]), $rt_dispatch_types, $type_args, $args)
};
($function:ident, ($rt_type:expr, [$($dispatch_type:ty),+]), $rt_dispatch_types:tt, $type_args:tt, $args:tt) => {
match $rt_type.id {
$(x if x == std::any::TypeId::of::<$dispatch_type>() => disp_1!($function, $rt_dispatch_types, $type_args, $dispatch_type, $args)),+,
_ => crate::ffi::dispatch::FailedDispatch::failed_dispatch($rt_type.descriptor.as_str())
}
};
}
pub trait FailedDispatch {
fn failed_dispatch(type_: &str) -> Self;
}
impl<T> FailedDispatch for Fallible<T> {
fn failed_dispatch(type_: &str) -> Self {
let debug_message = if cfg!(debug_assertions) {
"You've got a debug binary! Debug binaries support fewer types. Consult https://docs.opendp.org/en/stable/contributing/development-environment.html#build-opendp"
} else {
"See https://github.com/opendp/opendp/discussions/451."
};
fallible!(
FFI,
"No match for concrete type {}. {}",
type_,
debug_message
)
}
}
impl<T> FailedDispatch for FfiResult<*mut T> {
fn failed_dispatch(type_: &str) -> Self {
Fallible::<T>::failed_dispatch(type_).into()
}
}
impl<T> FailedDispatch for Option<T> {
fn failed_dispatch(_: &str) -> Self {
None
}
}
macro_rules! disp_1 {
($function:ident, $rt_dispatch_types:tt, ($($type_arg:ty),+), $type_arg_n:ty, $args:tt) => {
disp!($function, $rt_dispatch_types, ($($type_arg),+, $type_arg_n), $args)
};
($function:ident, $rt_dispatch_types:tt, (), $type_arg_n:ty, $args:tt) => {
disp!($function, $rt_dispatch_types, ($type_arg_n), $args)
};
}