n-observer-cffi-impl 0.1.0

CFFI logic without the C declarations for the n-observer rust library.
Documentation
// This file is autogenerated. Do not edit directly.
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};

use crate::CffiInnerObserverReceiver;

#[repr(C)]
#[derive(Debug, Clone)]
pub struct CffiPublisher {
    pub self_ptr: *const c_void,
    pub add_observer_fut:
        extern "C" fn(*const c_void, CffiInnerObserverReceiver, c_ulong) -> *const c_void,
    pub notify_fut: extern "C" fn(*const c_void, *const c_void) -> *const c_void,
}

impl Publisher for CffiPublisher {
    fn add_observer(
        &self,
        observer: Box<dyn InnerObserverReceiver>,
        input_index: usize,
    ) -> BoxFuture<'_, Option<AnyArc>> {
        let observer = {
            let cffi_observer = (*observer).into();

            Box::leak(observer); // Leak to keep alive

            cffi_observer
        };

        let input_index = input_index as c_ulong;

        let add_observer_fn = self.add_observer_fut;

        let self_ptr = SafePtr(self.self_ptr);

        Box::pin(async move {
            let self_ptr = self_ptr;

            let observer = observer;

            let input_index = input_index;

            let fut = (add_observer_fn)(self_ptr.0, observer, input_index);

            if fut.is_null() {
                panic!("C function returned null pointer");
            }

            let fut = unsafe {
                // Convert the raw pointer to a CffiFuture

                (fut as *mut CffiFuture)
                    .as_mut()
                    .expect("CffiFuture cannot be null")
            };

            let ret = fut.await;

            assert!(!ret.is_null());

            let ret = ret as *const *const c_void;

            let ret = *unsafe { ret.as_ref().unwrap() };

            let ret = if ret.is_null() {
                None
            } else {
                Some(Arc::new(SafePtr(ret)) as AnyArc)
            };

            ret
        })
    }
    fn notify(&self, data: AnyArc) -> BoxFuture<'_, ()> {
        let data = *data.downcast::<SafePtr>().expect("data must be SafePtr");

        let notify_fn = self.notify_fut;

        let self_ptr = SafePtr(self.self_ptr);

        Box::pin(async move {
            let self_ptr = self_ptr;

            let data = data;

            let fut = (notify_fn)(self_ptr.0, data.0);

            if fut.is_null() {
                panic!("C function returned null pointer");
            }

            let fut = unsafe {
                // Convert the raw pointer to a CffiFuture

                (fut as *mut CffiFuture)
                    .as_mut()
                    .expect("CffiFuture cannot be null")
            };

            fut.await;
        })
    }
}

unsafe impl Send for CffiPublisher {}

unsafe impl Sync for CffiPublisher {}

impl CffiPublisher {
    extern "C" fn add_observer_fut_impl(
        self_ptr: *const c_void,
        observer: CffiInnerObserverReceiver,
        input_index: c_ulong,
    ) -> *const c_void {
        let self_ref = unsafe {
            (self_ptr as *const &(dyn Publisher + Send + Sync))
                .as_ref()
                .expect("Self pointer cannot be null")
        };

        let observer = Box::new(observer);

        let input_index = input_index as usize;

        let fut = Box::pin(async move {
            let ret = self_ref.add_observer(observer, input_index).await;

            let ret = ret
                .map(|ret| ret.downcast::<SafePtr>().unwrap().0)
                .unwrap_or(std::ptr::null());

            SafePtr(ret)
        });

        CffiFuture::from_rust_future_boxed(fut).into_raw()
    }
    extern "C" fn notify_fut_impl(self_ptr: *const c_void, data: *const c_void) -> *const c_void {
        let self_ref = unsafe {
            (self_ptr as *const &(dyn Publisher + Send + Sync))
                .as_ref()
                .expect("Self pointer cannot be null")
        };

        let data = Arc::new(SafePtr(data));

        let fut = self_ref.notify(data);

        CffiFuture::from_rust_future_boxed(fut).into_raw()
    }
}

impl From<&dyn Publisher> for CffiPublisher {
    fn from(inner: &dyn Publisher) -> Self {
        CffiPublisher {
            // Wrap the fat pointer in a Box to get a stable address

            // Leak it to keep [just the wrapper] alive
            self_ptr: Box::into_raw(Box::new(inner)) as *const c_void,

            add_observer_fut: CffiPublisher::add_observer_fut_impl,

            notify_fut: CffiPublisher::notify_fut_impl,
        }
    }
}