#[macro_export]
macro_rules! ffi_safe {
($($ty:ty),*) => {
$(
impl $crate::IntoFFI for $ty {
type FFI = $ty;
fn into_ffi(self) -> Self::FFI {
self
}
}
impl $crate::IntoRust for $ty{
type Rust=$ty;
unsafe fn into_rust(self) -> Self::Rust{
self
}
}
)*
};
}
#[macro_export]
macro_rules! ffi_view {
($view:ty, $ffi:ty, $ident:tt) => {
$crate::ffi_view!($view, $ffi, $ident, all(), all());
};
($view:ty, $ffi:ty, $ident:tt, $jni:meta) => {
$crate::ffi_view!($view, $ffi, $ident, $jni, $jni);
};
($view:ty, $ffi:ty, $ident:tt, $jni_id:meta, $jni_force:meta) => {
pastey::paste! {
#[cfg(feature = "c-api")]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn [<waterui_force_as_ $ident>](view: *mut $crate::WuiAnyView) -> $ffi {
unsafe {
let any: waterui::AnyView = $crate::IntoRust::into_rust(view);
let view = (*any.downcast_unchecked::<waterui_core::Native<$view>>());
$crate::IntoFFI::into_ffi(view)
}
}
#[cfg(feature = "c-api")]
#[unsafe(no_mangle)]
pub extern "C" fn [<waterui_ $ident _id>]() -> $crate::WuiTypeId {
$crate::WuiTypeId::of::<waterui_core::Native<$view>>()
}
#[cfg(all(feature = "android-jni", $jni_id))]
#[unsafe(no_mangle)]
extern "system" fn [<Java_dev_waterui_android_ffi_WatcherJni_ $ident:lower_camel Id>]<'local>(
mut env: $crate::jni::JNIEnv<'local>,
_class: $crate::jni::JClass<'local>,
) -> $crate::jni::jobject {
$crate::jni::with_env(&mut env, |env| {
let type_id = $crate::WuiTypeId::of::<waterui_core::Native<$view>>();
$crate::jni::type_id_to_java(env, type_id).into_raw()
})
}
#[cfg(all(feature = "android-jni", $jni_force))]
#[unsafe(no_mangle)]
unsafe extern "system" fn [<Java_dev_waterui_android_ffi_WatcherJni_forceAs $ident:camel>]<'local>(
mut env: $crate::jni::JNIEnv<'local>,
_class: $crate::jni::JClass<'local>,
view_ptr: $crate::jni::jlong,
) -> $crate::jni::jobject {
use $crate::jni::convert::jlong_to_ptr_mut;
$crate::jni::with_env(&mut env, |env| unsafe {
let view_ptr: *mut $crate::WuiAnyView = jlong_to_ptr_mut(view_ptr);
let any: waterui::AnyView = $crate::IntoRust::into_rust(view_ptr);
let view = (*any.downcast_unchecked::<waterui_core::Native<$view>>());
let ffi_struct: $ffi = $crate::IntoFFI::into_ffi(view);
$crate::jni::convert::struct_to_java(env, &ffi_struct).into_raw()
})
}
}
};
}
#[macro_export]
macro_rules! ffi_metadata {
($ty:ty, $ffi:ty, $ident:tt) => {
$crate::ffi_metadata!($ty, $ffi, $ident, all(), all());
};
($ty:ty, $ffi:ty, $ident:tt, $jni:meta) => {
$crate::ffi_metadata!($ty, $ffi, $ident, $jni, $jni);
};
($ty:ty, $ffi:ty, $ident:tt, $jni_id:meta, $jni_force:meta) => {
pastey::paste! {
#[cfg(feature = "c-api")]
#[unsafe(no_mangle)]
pub extern "C" fn [<waterui_metadata_ $ident _id>]() -> $crate::WuiTypeId {
$crate::WuiTypeId::of::<waterui_core::Metadata<$ty>>()
}
#[cfg(feature = "c-api")]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn [<waterui_force_as_metadata_ $ident>](
view: *mut $crate::WuiAnyView
) -> $ffi {
unsafe {
let any: waterui::AnyView = $crate::IntoRust::into_rust(view);
let metadata = *any.downcast_unchecked::<waterui_core::Metadata<$ty>>();
$crate::IntoFFI::into_ffi(metadata)
}
}
#[cfg(all(feature = "android-jni", $jni_id))]
#[unsafe(no_mangle)]
extern "system" fn [<Java_dev_waterui_android_ffi_WatcherJni_metadata $ident:camel Id>]<'local>(
mut env: $crate::jni::JNIEnv<'local>,
_class: $crate::jni::JClass<'local>,
) -> $crate::jni::jobject {
$crate::jni::with_env(&mut env, |env| {
let type_id = $crate::WuiTypeId::of::<waterui_core::Metadata<$ty>>();
$crate::jni::type_id_to_java(env, type_id).into_raw()
})
}
#[cfg(all(feature = "android-jni", $jni_force))]
#[unsafe(no_mangle)]
unsafe extern "system" fn [<Java_dev_waterui_android_ffi_WatcherJni_forceAsMetadata $ident:camel>]<'local>(
mut env: $crate::jni::JNIEnv<'local>,
_class: $crate::jni::JClass<'local>,
view_ptr: $crate::jni::jlong,
) -> $crate::jni::jobject {
use $crate::jni::convert::jlong_to_ptr_mut;
$crate::jni::with_env(&mut env, |env| unsafe {
let view_ptr: *mut $crate::WuiAnyView = jlong_to_ptr_mut(view_ptr);
let any: waterui::AnyView = $crate::IntoRust::into_rust(view_ptr);
let metadata = *any.downcast_unchecked::<waterui_core::Metadata<$ty>>();
let ffi_struct: $ffi = $crate::IntoFFI::into_ffi(metadata);
$crate::jni::convert::struct_to_java(env, &ffi_struct).into_raw()
})
}
}
};
}
#[macro_export]
macro_rules! ffi_ignorable_metadata {
($ty:ty, $ffi:ty, $ident:tt) => {
pastey::paste! {
#[cfg(feature = "c-api")]
#[unsafe(no_mangle)]
pub extern "C" fn [<waterui_ignorable_metadata_ $ident _id>]() -> $crate::WuiTypeId {
$crate::WuiTypeId::of::<waterui_core::IgnorableMetadata<$ty>>()
}
#[cfg(feature = "c-api")]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn [<waterui_force_as_ignorable_metadata_ $ident>](
view: *mut $crate::WuiAnyView
) -> $ffi {
unsafe {
let any: waterui::AnyView = $crate::IntoRust::into_rust(view);
let metadata = *any.downcast_unchecked::<waterui_core::IgnorableMetadata<$ty>>();
$crate::IntoFFI::into_ffi(metadata)
}
}
#[cfg(feature = "android-jni")]
#[unsafe(no_mangle)]
extern "system" fn [<Java_dev_waterui_android_ffi_WatcherJni_ignorableMetadata $ident:camel Id>]<'local>(
mut env: $crate::jni::JNIEnv<'local>,
_class: $crate::jni::JClass<'local>,
) -> $crate::jni::jobject {
$crate::jni::with_env(&mut env, |env| {
let type_id = $crate::WuiTypeId::of::<waterui_core::IgnorableMetadata<$ty>>();
$crate::jni::type_id_to_java(env, type_id).into_raw()
})
}
#[cfg(feature = "android-jni")]
#[unsafe(no_mangle)]
unsafe extern "system" fn [<Java_dev_waterui_android_ffi_WatcherJni_forceAsIgnorableMetadata $ident:camel>]<'local>(
mut env: $crate::jni::JNIEnv<'local>,
_class: $crate::jni::JClass<'local>,
view_ptr: $crate::jni::jlong,
) -> $crate::jni::jobject {
use $crate::jni::convert::jlong_to_ptr_mut;
$crate::jni::with_env(&mut env, |env| unsafe {
let view_ptr: *mut $crate::WuiAnyView = jlong_to_ptr_mut(view_ptr);
let any: waterui::AnyView = $crate::IntoRust::into_rust(view_ptr);
let metadata = *any.downcast_unchecked::<waterui_core::IgnorableMetadata<$ty>>();
let ffi_struct: $ffi = $crate::IntoFFI::into_ffi(metadata);
$crate::jni::convert::struct_to_java(env, &ffi_struct).into_raw()
})
}
}
};
}
#[macro_export]
macro_rules! opaque {
($name:ident,$ty:ty,$ident:tt,$jni_drop:meta) => {
#[allow(nonstandard_style)]
#[doc = concat!("Opaque FFI handle owning a `", stringify!($ty), "`.")]
pub struct $name(pub(crate) $ty);
impl core::fmt::Debug for $name {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct(stringify!($name)).finish_non_exhaustive()
}
}
$crate::impl_deref!($name, $ty);
impl $crate::IntoFFI for $ty {
type FFI = *mut $name;
fn into_ffi(self) -> Self::FFI {
alloc::boxed::Box::into_raw(alloc::boxed::Box::new($name(self)))
}
}
impl $crate::IntoFFI for Option<$ty> {
type FFI = *mut $name;
fn into_ffi(self) -> Self::FFI {
if let Some(value) = self {
value.into_ffi()
} else {
core::ptr::null_mut::<$name>()
}
}
}
impl $crate::IntoRust for *mut $name {
type Rust = $ty;
unsafe fn into_rust(self) -> Self::Rust {
unsafe { alloc::boxed::Box::from_raw(self).0 }
}
}
pastey::paste! {
#[cfg(feature = "c-api")]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn [<waterui_drop_ $ident>](value: *mut $name) {
unsafe {
let _ = $crate::IntoRust::into_rust(value);
}
}
#[cfg(all(feature = "android-jni", $jni_drop))]
#[unsafe(no_mangle)]
unsafe extern "system" fn [<Java_dev_waterui_android_ffi_WatcherJni_drop $ident:camel>]<'local>(
_env: $crate::jni::JNIEnv<'local>,
_class: $crate::jni::JClass<'local>,
ptr: $crate::jni::jlong,
) {
use $crate::jni::convert::jlong_to_ptr_mut;
unsafe {
let ptr: *mut $name = jlong_to_ptr_mut(ptr);
let _ = $crate::IntoRust::into_rust(ptr);
}
}
}
};
($name:ident,$ty:ty,$ident:tt) => {
$crate::opaque!($name, $ty, $ident, all());
};
($name:ident,$ty:ty) => {
pastey::paste! {
$crate::opaque!($name,$ty,[<$ty:snake>]);
}
};
}
macro_rules! into_ffi {
($ty:ty, $(#[$meta:meta])* pub struct $ffi:ident { $($field:ident : $ftype:ty),* $(,)? }) => {
#[doc = concat!("C ABI mirror of `", stringify!($ty), "`.")]
$(#[$meta])*
#[derive(Debug)]
#[repr(C)]
pub struct $ffi {
$(
#[doc = concat!("Mirrors the `", stringify!($field), "` field of `", stringify!($ty), "`.")]
pub $field: $ftype
),*
}
impl $crate::IntoFFI for $ty {
type FFI = $ffi;
fn into_ffi(self) -> Self::FFI {
let value = self;
$ffi {
$($field: $crate::IntoFFI::into_ffi(value.$field)),*
}
}
}
};
($ty:ty, $(#[$meta:meta])* pub enum $ffi:ident { $($variant:ident),* $(,)? }) => {
#[doc = concat!("C ABI mirror of `", stringify!($ty), "`.")]
$(#[$meta])*
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub enum $ffi {
$(
#[doc = concat!("Mirrors `", stringify!($ty), "::", stringify!($variant), "`.")]
$variant
),*
}
impl $crate::IntoFFI for $ty {
type FFI = $ffi;
fn into_ffi(self) -> Self::FFI {
match self {
$(<$ty>::$variant => $ffi::$variant),*
}
}
}
impl $crate::IntoRust for $ffi {
type Rust = $ty;
unsafe fn into_rust(self) -> Self::Rust {
match self {
$( $ffi::$variant => <$ty>::$variant ),*
}
}
}
};
($ty:ty, non_exhaustive, $(#[$meta:meta])* pub enum $ffi:ident { $($variant:ident),* $(,)? }) => {
#[doc = concat!("C ABI mirror of `", stringify!($ty), "`.")]
$(#[$meta])*
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub enum $ffi {
$(
#[doc = concat!("Mirrors `", stringify!($ty), "::", stringify!($variant), "`.")]
$variant
),*
}
impl $crate::IntoFFI for $ty {
type FFI = $ffi;
fn into_ffi(self) -> Self::FFI {
match self {
$(<$ty>::$variant => $ffi::$variant),*,
_ => panic!(concat!("unsupported ", stringify!($ty), " variant")),
}
}
}
impl $crate::IntoRust for $ffi {
type Rust = $ty;
unsafe fn into_rust(self) -> Self::Rust {
match self {
$( $ffi::$variant => <$ty>::$variant ),*
}
}
}
};
}
#[macro_export]
macro_rules! impl_deref {
($ty:ty,$target:ty) => {
impl core::ops::Deref for $ty {
type Target = $target;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl core::ops::DerefMut for $ty {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
};
}