n_observer_cffi_impl/
publisher_cffi_traits.rs1use std::{
3 ffi::{c_ulong, c_void},
4 sync::Arc,
5};
6
7use async_cffi::{CffiFuture, CffiPointerBuffer, SafePtr};
8
9use futures::future::BoxFuture;
10
11use n_observer::{AnyArc, InnerObserverReceiver, Observable, Publisher};
12
13use crate::CffiInnerObserverReceiver;
14
15#[repr(C)]
16#[derive(Debug, Clone)]
17pub struct CffiPublisher {
18 pub self_ptr: *const c_void,
19 pub add_observer_fut:
20 extern "C" fn(*const c_void, CffiInnerObserverReceiver, c_ulong) -> *const c_void,
21 pub notify_fut: extern "C" fn(*const c_void, *const c_void) -> *const c_void,
22}
23
24impl Publisher for CffiPublisher {
25 fn add_observer(
26 &self,
27 observer: Box<dyn InnerObserverReceiver>,
28 input_index: usize,
29 ) -> BoxFuture<'_, Option<AnyArc>> {
30 let observer = {
31 let cffi_observer = (*observer).into();
32
33 Box::leak(observer); cffi_observer
36 };
37
38 let input_index = input_index as c_ulong;
39
40 let add_observer_fn = self.add_observer_fut;
41
42 let self_ptr = SafePtr(self.self_ptr);
43
44 Box::pin(async move {
45 let self_ptr = self_ptr;
46
47 let observer = observer;
48
49 let input_index = input_index;
50
51 let fut = (add_observer_fn)(self_ptr.0, observer, input_index);
52
53 if fut.is_null() {
54 panic!("C function returned null pointer");
55 }
56
57 let fut = unsafe {
58 (fut as *mut CffiFuture)
61 .as_mut()
62 .expect("CffiFuture cannot be null")
63 };
64
65 let ret = fut.await;
66
67 assert!(!ret.is_null());
68
69 let ret = ret as *const *const c_void;
70
71 let ret = *unsafe { ret.as_ref().unwrap() };
72
73 let ret = if ret.is_null() {
74 None
75 } else {
76 Some(Arc::new(SafePtr(ret)) as AnyArc)
77 };
78
79 ret
80 })
81 }
82 fn notify(&self, data: AnyArc) -> BoxFuture<'_, ()> {
83 let data = *data.downcast::<SafePtr>().expect("data must be SafePtr");
84
85 let notify_fn = self.notify_fut;
86
87 let self_ptr = SafePtr(self.self_ptr);
88
89 Box::pin(async move {
90 let self_ptr = self_ptr;
91
92 let data = data;
93
94 let fut = (notify_fn)(self_ptr.0, data.0);
95
96 if fut.is_null() {
97 panic!("C function returned null pointer");
98 }
99
100 let fut = unsafe {
101 (fut as *mut CffiFuture)
104 .as_mut()
105 .expect("CffiFuture cannot be null")
106 };
107
108 fut.await;
109 })
110 }
111}
112
113unsafe impl Send for CffiPublisher {}
114
115unsafe impl Sync for CffiPublisher {}
116
117impl CffiPublisher {
118 extern "C" fn add_observer_fut_impl(
119 self_ptr: *const c_void,
120 observer: CffiInnerObserverReceiver,
121 input_index: c_ulong,
122 ) -> *const c_void {
123 let self_ref = unsafe {
124 (self_ptr as *const &(dyn Publisher + Send + Sync))
125 .as_ref()
126 .expect("Self pointer cannot be null")
127 };
128
129 let observer = Box::new(observer);
130
131 let input_index = input_index as usize;
132
133 let fut = Box::pin(async move {
134 let ret = self_ref.add_observer(observer, input_index).await;
135
136 let ret = ret
137 .map(|ret| ret.downcast::<SafePtr>().unwrap().0)
138 .unwrap_or(std::ptr::null());
139
140 SafePtr(ret)
141 });
142
143 CffiFuture::from_rust_future_boxed(fut).into_raw()
144 }
145 extern "C" fn notify_fut_impl(self_ptr: *const c_void, data: *const c_void) -> *const c_void {
146 let self_ref = unsafe {
147 (self_ptr as *const &(dyn Publisher + Send + Sync))
148 .as_ref()
149 .expect("Self pointer cannot be null")
150 };
151
152 let data = Arc::new(SafePtr(data));
153
154 let fut = self_ref.notify(data);
155
156 CffiFuture::from_rust_future_boxed(fut).into_raw()
157 }
158}
159
160impl From<&dyn Publisher> for CffiPublisher {
161 fn from(inner: &dyn Publisher) -> Self {
162 CffiPublisher {
163 self_ptr: Box::into_raw(Box::new(inner)) as *const c_void,
167
168 add_observer_fut: CffiPublisher::add_observer_fut_impl,
169
170 notify_fut: CffiPublisher::notify_fut_impl,
171 }
172 }
173}