use self::cast::metacallobj_untyped_to_raw;
use super::{MetaCallNull, MetaCallValue};
use crate::{
bindings::{
metacall_await_future, metacall_value_create_null, metacall_value_destroy,
metacall_value_to_future,
},
cast,
};
use std::{
any::Any,
ffi::c_void,
fmt::{self, Debug, Formatter},
ptr::null_mut,
};
pub type MetaCallFutureHandler =
fn(Box<dyn MetaCallValue>, Option<Box<dyn Any>>) -> Box<dyn MetaCallValue>;
#[repr(C)]
pub struct MetaCallFuture {
data: *mut dyn Any,
leak: bool,
reject: Option<MetaCallFutureHandler>,
resolve: Option<MetaCallFutureHandler>,
value: *mut c_void,
}
unsafe impl Send for MetaCallFuture {}
unsafe impl Sync for MetaCallFuture {}
impl Clone for MetaCallFuture {
fn clone(&self) -> Self {
Self {
data: self.data,
leak: true,
reject: self.reject,
resolve: self.resolve,
value: self.value,
}
}
}
impl Debug for MetaCallFuture {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let boxed_data = unsafe { Box::from_raw(self.data) };
let data = if boxed_data.is::<MetaCallNull>() {
None
} else {
Some(format!("{:#?}", boxed_data))
};
Box::leak(boxed_data);
let resolve = if self.resolve.is_none() {
"None"
} else {
"Some"
};
let reject = if self.reject.is_none() {
"None"
} else {
"Some"
};
f.debug_struct("MetaCallFuture")
.field("data", &data)
.field("resolve", &resolve)
.field("reject", &reject)
.finish()
}
}
type MetaCallFutureFFIData = (
Option<MetaCallFutureHandler>,
Option<MetaCallFutureHandler>,
*mut dyn Any,
);
unsafe extern "C" fn resolver(resolve_data: *mut c_void, upper_data: *mut c_void) -> *mut c_void {
let (resolve, _, data) = *Box::from_raw(upper_data as *mut MetaCallFutureFFIData);
let user_data = if !data.is_null() {
Some(Box::from_raw(data))
} else {
None
};
let result = (resolve.unwrap())(
cast::raw_to_metacallobj_untyped_leak(resolve_data),
user_data,
);
if let Some(ret) = metacallobj_untyped_to_raw(result) {
return ret;
}
unsafe { metacall_value_create_null() }
}
unsafe extern "C" fn rejecter(reject_data: *mut c_void, upper_data: *mut c_void) -> *mut c_void {
let (_, reject, data) = *Box::from_raw(upper_data as *mut MetaCallFutureFFIData);
let user_data = if !data.is_null() {
Some(Box::from_raw(data))
} else {
None
};
let result = (reject.unwrap())(
cast::raw_to_metacallobj_untyped_leak(reject_data),
user_data,
);
if let Some(ret) = metacallobj_untyped_to_raw(result) {
return ret;
}
unsafe { metacall_value_create_null() }
}
impl MetaCallFuture {
#[doc(hidden)]
pub fn new_raw(value: *mut c_void) -> Self {
Self {
data: null_mut::<()>(),
leak: false,
reject: None,
resolve: None,
value,
}
}
#[doc(hidden)]
pub fn new_raw_leak(value: *mut c_void) -> Self {
Self {
data: null_mut::<()>(),
leak: true,
reject: None,
resolve: None,
value,
}
}
pub fn then(mut self, resolve: MetaCallFutureHandler) -> Self {
self.resolve = Some(resolve);
self
}
pub fn catch(mut self, reject: MetaCallFutureHandler) -> Self {
self.reject = Some(reject);
self
}
pub fn data<T: 'static>(mut self, data: T) -> Self {
self.data = Box::into_raw(Box::new(data));
self
}
pub fn await_fut(self) {
let resolve_is_some = self.resolve.is_some();
let reject_is_some = self.reject.is_some();
unsafe {
metacall_value_destroy(metacall_await_future(
metacall_value_to_future(self.value),
if resolve_is_some {
Some(resolver)
} else {
None
},
if reject_is_some { Some(rejecter) } else { None },
Box::into_raw(Box::new((self.resolve, self.reject, self.data))) as *mut c_void,
))
};
}
#[doc(hidden)]
pub fn into_raw(self) -> *mut c_void {
panic!("Passing MetaCallFuture as an argument is not supported!");
}
}
impl Drop for MetaCallFuture {
fn drop(&mut self) {
if !self.leak {
unsafe { metacall_value_destroy(self.value) };
}
}
}