qwac-sys 0.28.1

The FFI crates for QWAC
Documentation
use std::{
    future::Future,
    ops::{Deref, DerefMut},
    pin::Pin,
    ptr::null_mut,
    sync::{
        atomic::{AtomicBool, Ordering},
        Arc,
    },
    task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
};

pub mod audio;
pub mod core;
pub mod data;
pub mod graphics;
pub mod input;

#[derive(Debug)]
struct Promise {
    index: i32,
    resolved: AtomicBool,
}

impl From<i32> for Promise {
    fn from(index: i32) -> Self {
        Self {
            index,
            resolved: AtomicBool::new(false),
        }
    }
}

impl Promise {
    /// Resolve the promise only if it's not resolved already.
    fn resolve(&self) {
        if !self.resolved.swap(true, Ordering::Relaxed) {
            unsafe {
                crate::core::resolve_promise(self.index);
            }
        }
    }
}

mod vtable {
    use crate::Promise;
    use std::mem::ManuallyDrop;
    use std::sync::Arc;
    use std::task::RawWaker;

    pub unsafe fn clone(data: *const ()) -> RawWaker {
        Arc::increment_strong_count(data as *const Promise);
        RawWaker::new(data, &crate::V_TABLE)
    }
    pub unsafe fn wake(data: *const ()) {
        let data = Arc::from_raw(data as *const Promise);
        data.resolve();
    }
    pub unsafe fn wake_by_ref(data: *const ()) {
        let data = ManuallyDrop::new(Arc::from_raw(data as *const Promise));
        data.resolve();
    }
    pub unsafe fn drop(data: *const ()) {
        std::mem::drop(Arc::from_raw(data as *const Promise));
    }
}

const V_TABLE: RawWakerVTable = RawWakerVTable::new(
    vtable::clone,
    vtable::wake,
    vtable::wake_by_ref,
    vtable::drop,
);

/// A buffer type, allowing abstracting away the internal implementation without breaking API.
#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
#[repr(transparent)]
pub struct Buffer(Box<[u8]>);

impl Buffer {
    fn new(size: usize) -> Self {
        let mut vec = Vec::new();
        vec.reserve_exact(size);
        vec.resize(size, 0);
        Self(vec.into_boxed_slice())
    }
}

impl Deref for Buffer {
    type Target = [u8];

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for Buffer {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl From<Buffer> for Box<[u8]> {
    fn from(value: Buffer) -> Self {
        value.0
    }
}
impl From<Buffer> for Vec<u8> {
    fn from(value: Buffer) -> Self {
        value.0.into_vec()
    }
}

#[no_mangle]
pub extern "C" fn qwac_buffer_create(size: i32) -> *mut Buffer {
    let buffer = Buffer::new(size.try_into().expect("Out of range"));
    Box::into_raw(Box::new(buffer))
}

#[no_mangle]
pub extern "C" fn qwac_buffer_pointer(buffer: *mut Buffer) -> *mut u8 {
    let buffer = unsafe { &mut *buffer };
    buffer.as_mut_ptr()
}

#[no_mangle]
pub extern "C" fn qwac_poll(
    raw_future: *mut Pin<Box<dyn Future<Output = ()>>>,
    promise: i32,
) -> *mut Pin<Box<dyn Future<Output = ()>>> {
    let future = unsafe { &mut *raw_future }.as_mut();
    let data: Arc<Promise> = Arc::new(promise.into());
    let data = Arc::into_raw(data) as *const ();
    let raw_waker = RawWaker::new(data, &V_TABLE);
    let waker = unsafe { Waker::from_raw(raw_waker) };
    let mut context = Context::from_waker(&waker);
    match future.poll(&mut context) {
        Poll::Ready(()) => {
            // Finishing a future drops it as well.
            unsafe {
                drop(Box::from_raw(raw_future));
            }
            null_mut()
        }
        Poll::Pending => raw_future,
    }
}