use std::{
ffi::{c_ulong, c_void},
sync::Arc,
};
use async_cffi::{CffiFuture, CffiPointerBuffer, SafePtr};
use futures::future::BoxFuture;
use n_observer::{AnyArc, InnerObserverReceiver, Observable, Publisher};
#[repr(C)]
#[derive(Debug, Clone)]
pub struct CffiInnerObserverReceiver {
pub self_ptr: *const c_void,
pub update_fut: extern "C" fn(*const c_void, CffiPointerBuffer) -> *const c_void,
pub hold_strong_publisher_ref_fut: extern "C" fn(*const c_void, *const c_void) -> *const c_void,
}
impl InnerObserverReceiver for CffiInnerObserverReceiver {
fn update(&self, data: Vec<Option<AnyArc>>) -> BoxFuture<'_, ()> {
let data = CffiPointerBuffer::from_slice(
data.into_iter()
.map(|data| {
(if let Some(data) = data {
*data.downcast::<SafePtr>().expect("data must be SafePtr")
} else {
SafePtr(std::ptr::null())
})
.0
})
.collect::<Box<[_]>>(),
);
let update_fn = self.update_fut;
let self_ptr = SafePtr(self.self_ptr);
Box::pin(async move {
let self_ptr = self_ptr;
let data = data;
let fut = (update_fn)(self_ptr.0, data);
if fut.is_null() {
panic!("C function returned null pointer");
}
let fut = unsafe {
(fut as *mut CffiFuture)
.as_mut()
.expect("CffiFuture cannot be null")
};
fut.await;
})
}
fn hold_strong_publisher_ref(
&self,
publisher: Arc<dyn Publisher + Send + Sync>,
) -> BoxFuture<'_, ()> {
let publisher = SafePtr(Arc::into_raw(publisher) as *const c_void);
let hold_strong_publisher_ref_fn = self.hold_strong_publisher_ref_fut;
let self_ptr = SafePtr(self.self_ptr);
Box::pin(async move {
let self_ptr = self_ptr;
let publisher = publisher;
let fut = (hold_strong_publisher_ref_fn)(self_ptr.0, publisher.0);
if fut.is_null() {
panic!("C function returned null pointer");
}
let fut = unsafe {
(fut as *mut CffiFuture)
.as_mut()
.expect("CffiFuture cannot be null")
};
fut.await;
})
}
}
unsafe impl Send for CffiInnerObserverReceiver {}
unsafe impl Sync for CffiInnerObserverReceiver {}
impl CffiInnerObserverReceiver {
extern "C" fn update_fut_impl(
self_ptr: *const c_void,
data: CffiPointerBuffer,
) -> *const c_void {
let self_ref = unsafe {
(self_ptr as *const &(dyn InnerObserverReceiver + Send + Sync))
.as_ref()
.expect("Self pointer cannot be null")
};
let data = data
.as_slice()
.iter()
.copied()
.map(|value| {
if !value.is_null() {
let value = SafePtr(value);
Some(Arc::new(value) as AnyArc)
} else {
None
}
})
.collect();
let fut = self_ref.update(data);
CffiFuture::from_rust_future_boxed(fut).into_raw()
}
extern "C" fn hold_strong_publisher_ref_fut_impl(
self_ptr: *const c_void,
publisher: *const c_void,
) -> *const c_void {
CffiFuture::from_rust_future_boxed(async move {}).into_raw()
}
}
impl From<&dyn InnerObserverReceiver> for CffiInnerObserverReceiver {
fn from(inner: &dyn InnerObserverReceiver) -> Self {
CffiInnerObserverReceiver {
self_ptr: Box::into_raw(Box::new(inner)) as *const c_void,
update_fut: CffiInnerObserverReceiver::update_fut_impl,
hold_strong_publisher_ref_fut:
CffiInnerObserverReceiver::hold_strong_publisher_ref_fut_impl,
}
}
}