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 {
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,
);
#[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(()) => {
unsafe {
drop(Box::from_raw(raw_future));
}
null_mut()
}
Poll::Pending => raw_future,
}
}