use super::application::ApplicationHandle;
use browser_window_ffi::*;
use std::boxed::Box;
use std::future::Future;
use std::mem;
use std::os::raw::*;
use std::panic;
use std::pin::Pin;
use std::rc::Rc;
use std::sync::Arc;
use std::task::{
Context,
Poll,
Waker
};
use std::panic::{AssertUnwindSafe, catch_unwind};
struct DelegateData<'a,'b,H,R> {
handle: H,
result: &'a mut Option<Result<R, DelegateError>>,
func: Box<dyn FnOnce( H ) -> R + Send + 'b>,
waker: Waker
}
struct DelegateFutureData<'a,'b,R> where R: Send{
inner: &'b mut DelegateFutureInner<'a,R>,
waker: Waker
}
#[derive(Debug)]
pub enum DelegateError {
RuntimeNotAvailable,
ClosurePanicked
}
pub struct DelegateFuture<'a,H,R> where
R: Send
{
handle: H,
func: Option<Box<dyn FnOnce( H ) -> R + Send + 'a>>,
result: Option<Result<R, DelegateError>>,
started: bool
}
impl<'a,H,R> Unpin for DelegateFuture<'a,H,R> where R: Send {}
unsafe impl<'a,H,R> Send for DelegateFuture<'a,H,R> where R: Send {}
pub struct DelegateFutureFuture<'a,R> where
R: Send
{
app_handle: ApplicationHandle,
inner: DelegateFutureInner<'a,R>,
started: bool
}
unsafe impl<'a,R> Send for DelegateFutureFuture<'a,R> where R: Send {}
impl<'a,R> Unpin for DelegateFutureFuture<'a,R> where R: Send {}
struct DelegateFutureInner<'a,R> where R: Send {
result: Option<Result<R, DelegateError>>,
future: Pin<Box<dyn Future<Output=R> + 'a>>
}
unsafe impl<'a,R> Send for DelegateFutureInner<'a,R> where R: Send {}
impl<'a,H,R> DelegateFuture<'a,H,R> where R: Send {
pub(in super) fn new<F>( handle: H, func: F ) -> Self where
F: FnOnce( H ) -> R + Send + 'a,
R: Send
{
Self {
handle,
func: Some( Box::new( func ) ),
result: None,
started: false
}
}
}
impl<'a,H,R> Future for DelegateFuture<'a,H,R> where
H: HasAppHandle + Clone + 'static,
R: Send + 'static
{
type Output = Result<R, DelegateError>;
fn poll( mut self: Pin<&mut Self>, cx: &mut Context ) -> Poll<Self::Output> {
if !self.started {
self.started = true;
let app_ffi_handle = self.handle.app_handle().ffi_handle;
let mut func = None;
mem::swap( &mut self.func, &mut func );
let data = DelegateData {
handle: self.handle.clone(),
func: func.unwrap(),
result: &mut self.result,
waker: cx.waker().clone()
};
let succeeded = unsafe {
let data_ptr = Box::into_raw( Box::new( data ) );
bw_Application_dispatch(
app_ffi_handle,
ffi_delegate_handler::<H,R>,
data_ptr as _
)
};
if !succeeded {
return Poll::Ready( Err( DelegateError::RuntimeNotAvailable ) );
}
Poll::Pending
}
else {
if self.result.is_none() {
return Poll::Pending;
}
let mut temp: Option<Result<R, DelegateError>> = None;
mem::swap( &mut self.result, &mut temp );
Poll::Ready( temp.unwrap() )
}
}
}
impl<'a,R> DelegateFutureFuture<'a,R> where R: Send {
pub(in super) fn new( app_handle: ApplicationHandle, future: impl Future<Output=R> + 'a ) -> Self {
Self {
app_handle,
inner: DelegateFutureInner {
result: None,
future: Box::pin( future )
},
started: false
}
}
}
impl<'a,R> Future for DelegateFutureFuture<'a,R> where R: Send {
type Output = Result<R, DelegateError>;
fn poll( mut self: Pin<&mut Self>, ctx: &mut Context ) -> Poll<Self::Output> {
if !self.started {
self.started = true;
let app_ffi_handle = self.app_handle.ffi_handle;
let succeeded = unsafe {
let data_ptr = Box::into_raw(Box::new(DelegateFutureData {
inner: &mut self.inner,
waker: ctx.waker().clone(),
}));
bw_Application_dispatch(
app_ffi_handle,
ffi_delegate_async_handler::<R>,
data_ptr as _
)
};
if !succeeded {
return Poll::Ready(Err(DelegateError::RuntimeNotAvailable));
}
Poll::Pending
}
else {
let mut temp: Option<Result<R, DelegateError>> = None;
mem::swap( &mut self.inner.result, &mut temp );
Poll::Ready( temp.unwrap() )
}
}
}
pub trait HasAppHandle {
fn app_handle( &self ) -> ApplicationHandle;
}
pub trait PointerEq {
fn ptr_eq( &self, other: &Self ) -> bool;
}
impl<T> PointerEq for Rc<T> {
fn ptr_eq( &self, other: &Self ) -> bool {
Rc::ptr_eq( self, other )
}
}
impl<T> PointerEq for Arc<T> {
fn ptr_eq( &self, other: &Self ) -> bool {
Arc::ptr_eq( self, other )
}
}
extern "C" fn ffi_delegate_handler<H,R>( app: *mut bw_Application, _data: *mut c_void ) where
H: Clone + 'static,
R: 'static
{
unsafe {
let data_ptr: *mut DelegateData<'static,'static,H,R> = mem::transmute( _data );
let data = Box::from_raw( data_ptr );
match *data {
DelegateData{ handle, func, result, waker } => {
match catch_unwind(AssertUnwindSafe(|| {
*result = Some( Ok( func( handle ) ) );
waker.clone().wake();
})) {
Ok(()) => {},
Err( _ ) => {
*result = Some(Err(DelegateError::ClosurePanicked));
waker.wake();
bw_Application_exit( app, -1 );
}
}
}
}
}
}
extern "C" fn ffi_delegate_async_handler<R>( app: *mut bw_Application, _data: *mut c_void ) where R: Send {
unsafe {
let data_ptr: *mut DelegateFutureData<R> = mem::transmute( _data );
let data = Box::from_raw( data_ptr );
match *data {
DelegateFutureData{ inner, waker } => {
match panic::catch_unwind(AssertUnwindSafe(|| {
let mut ctx = Context::from_waker( &waker );
match inner.future.as_mut().poll( &mut ctx ) {
Poll::Pending => {},
Poll::Ready( result) => {
inner.result = Some( Ok( result ) );
waker.clone().wake();
}
}
})) {
Ok(()) => {},
Err( _ ) => {
inner.result = Some(Err(DelegateError::ClosurePanicked));
waker.wake();
bw_Application_exit( app, -1 );
}
}
}
}
}
}