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

#[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 {
                // Convert the raw pointer to a CffiFuture

                (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 {
                // Convert the raw pointer to a CffiFuture

                (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 {
        // no-op

        CffiFuture::from_rust_future_boxed(async move {}).into_raw()
    }
}

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

            update_fut: CffiInnerObserverReceiver::update_fut_impl,

            hold_strong_publisher_ref_fut:
                CffiInnerObserverReceiver::hold_strong_publisher_ref_fut_impl,
        }
    }
}