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::CffiPublisher;

use crate::CffiInnerObserverReceiver;

#[repr(C)]
#[derive(Debug, Clone)]
pub struct CffiObservable {
    pub self_ptr: *const c_void,
    pub cffi_publisher: CffiPublisher,
    pub cffi_inner_observer_receiver: CffiInnerObserverReceiver,
    pub get_fut: extern "C" fn(*const c_void) -> *const c_void,
}

impl Publisher for CffiObservable {
    fn add_observer(
        &self,
        observer: Box<dyn InnerObserverReceiver>,
        input_index: usize,
    ) -> BoxFuture<'_, Option<AnyArc>> {
        self.as_publisher().add_observer(observer, input_index)
    }
    fn notify(&self, data: AnyArc) -> BoxFuture<'_, ()> {
        self.as_publisher().notify(data)
    }
}

impl InnerObserverReceiver for CffiObservable {
    fn update(&self, data: Vec<Option<AnyArc>>) -> BoxFuture<'_, ()> {
        self.as_inner_observer_receiver().update(data)
    }
    fn hold_strong_publisher_ref(
        &self,
        publisher: Arc<dyn Publisher + Send + Sync>,
    ) -> BoxFuture<'_, ()> {
        self.as_inner_observer_receiver()
            .hold_strong_publisher_ref(publisher)
    }
}

impl Observable<SafePtr> for CffiObservable {
    fn get(&self) -> BoxFuture<'_, Option<Arc<SafePtr>>> {
        let get_fn = self.get_fut;

        let self_ptr = SafePtr(self.self_ptr);

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

            let fut = (get_fn)(self_ptr.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")
            };

            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)))
            };

            ret
        })
    }
}

unsafe impl Send for CffiObservable {}

unsafe impl Sync for CffiObservable {}

impl CffiObservable {
    fn as_publisher(&self) -> &dyn Publisher {
        &self.cffi_publisher
    }
    fn as_inner_observer_receiver(&self) -> &dyn InnerObserverReceiver {
        &self.cffi_inner_observer_receiver
    }
    extern "C" fn get_fut_impl(self_ptr: *const c_void) -> *const c_void {
        let self_ref = unsafe {
            (self_ptr as *const &(dyn Observable<SafePtr> + Send + Sync))
                .as_ref()
                .expect("Self pointer cannot be null")
        };

        let fut = Box::pin(async move {
            let ret = self_ref.get().await;

            let ret = ret
                .map(|ret| {
                    let ret = *ret;

                    ret.0
                })
                .unwrap_or(std::ptr::null());

            SafePtr(ret)
        });

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

impl From<&dyn Observable<SafePtr>> for CffiObservable {
    fn from(inner: &dyn Observable<SafePtr>) -> Self {
        CffiObservable {
            // 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,

            cffi_publisher: {
                let publisher = Box::new(inner as &dyn Publisher);

                let ret: CffiPublisher = (*publisher).into();

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

                ret
            },

            cffi_inner_observer_receiver: {
                let inner_observer_receiver = Box::new(inner as &dyn InnerObserverReceiver);

                let ret: CffiInnerObserverReceiver = (*inner_observer_receiver).into();

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

                ret
            },

            get_fut: CffiObservable::get_fut_impl,
        }
    }
}