use std::{
boxed::Box,
future::Future,
mem, panic,
panic::{catch_unwind, AssertUnwindSafe},
pin::Pin,
task::{Context, Poll, Waker},
};
use crate::{application::ApplicationHandle, core::application::*, HasHandle};
struct DelegateData<'a, 'b, O, H, R> {
handle: O,
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, O, H, R>
where
R: Send,
{
handle: O,
func: Option<Box<dyn FnOnce(&H) -> R + Send + 'a>>,
result: Option<Result<R, DelegateError>>,
started: bool,
}
impl<'a, O, H, R> Unpin for DelegateFuture<'a, O, H, R> where R: Send {}
unsafe impl<'a, O, H, R> Send for DelegateFuture<'a, O, 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 {}
#[cfg(feature = "threadsafe")]
impl<'a, O, H, R> DelegateFuture<'a, O, H, R>
where
R: Send,
{
pub(super) fn new<F>(handle: O, func: F) -> Self
where
F: FnOnce(&H) -> R + Send + 'a,
R: Send,
{
Self {
handle,
func: Some(Box::new(func)),
result: None,
started: false,
}
}
}
#[cfg(feature = "threadsafe")]
impl<'a, O, H, R> Future for DelegateFuture<'a, O, H, R>
where
O: HasHandle<H> + HasHandle<ApplicationHandle> + Clone,
H: '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_inner = HasHandle::<ApplicationHandle>::handle(&self.handle)
.inner
.clone();
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 = {
let data_ptr = Box::into_raw(Box::new(data));
app_inner.dispatch(delegate_handler::<O, 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())
}
}
}
#[cfg(feature = "threadsafe")]
impl<'a, R> DelegateFutureFuture<'a, R>
where
R: Send,
{
pub(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,
}
}
}
#[cfg(feature = "threadsafe")]
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_inner = self.app_handle.inner.clone();
let data_ptr = Box::into_raw(Box::new(DelegateFutureData {
inner: &mut self.inner,
waker: ctx.waker().clone(),
}));
let succeeded = app_inner.dispatch(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())
}
}
}
fn delegate_handler<O, H, R>(app: ApplicationImpl, _data: *mut ())
where
H: 'static,
O: HasHandle<H>,
R: 'static,
{
let data_ptr = _data as *mut DelegateData<'static, 'static, O, H, R>;
let data = unsafe { Box::from_raw(data_ptr) };
match *data {
DelegateData {
handle,
func,
result,
waker,
} => {
match catch_unwind(AssertUnwindSafe(|| {
let h = handle.handle();
*result = Some(Ok(func(h)));
waker.clone().wake();
})) {
Ok(()) => {}
Err(_) => {
*result = Some(Err(DelegateError::ClosurePanicked));
waker.wake();
app.exit(-1);
}
}
}
}
}
#[cfg(feature = "threadsafe")]
fn delegate_async_handler<R>(app: ApplicationImpl, _data: *mut ())
where
R: Send,
{
let data_ptr = _data as *mut DelegateFutureData<R>;
let data = unsafe { 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();
app.exit(-1);
}
}
}
}
}