#[ allow(unused_imports) ] use
{
std :: { future::Future, sync::atomic::{ AtomicBool, Ordering } } ,
std :: { task::{ Poll, Context }, pin::Pin } ,
futures_util:: { future::{ AbortHandle, Aborted, RemoteHandle }, ready } ,
};
#[ cfg( feature = "async_global" ) ]
use async_global_executor::{ Task as AsyncGlobalTask };
#[ cfg( feature = "async_std" ) ]
use async_std_crate::{ task::JoinHandle as AsyncStdJoinHandle };
#[ cfg(any( feature = "tokio_tp", feature = "tokio_ct" )) ]
use tokio::{ task::JoinHandle as TokioJoinHandle };
#[ derive( Debug ) ]
#[ must_use = "JoinHandle will cancel your future when dropped." ]
pub struct JoinHandle<T> { pub(crate) inner: InnerJh<T> }
#[ derive(Debug) ] #[ allow(dead_code) ]
pub(crate) enum InnerJh<T>
{
#[ cfg(any( feature = "tokio_tp", feature = "tokio_ct" )) ]
Tokio
{
handle : TokioJoinHandle<T> ,
detached: AtomicBool ,
},
#[ cfg( feature = "async_global" ) ]
AsyncGlobal
{
task: Option< AsyncGlobalTask<T> > ,
},
#[ cfg( feature = "async_std" ) ]
AsyncStd
{
handle : AsyncStdJoinHandle<Result<T, Aborted>> ,
a_handle: AbortHandle ,
detached: AtomicBool ,
},
RemoteHandle( Option<RemoteHandle<T>> ),
}
impl<T> JoinHandle<T>
{
pub fn detach( mut self )
{
match &mut self.inner
{
#[ cfg(any( feature = "tokio_tp", feature = "tokio_ct" )) ]
InnerJh::Tokio{ ref detached, .. } =>
{
detached.store( true, Ordering::Relaxed );
}
#[ cfg( feature = "async_global" ) ] InnerJh::AsyncGlobal{ task } =>
{
let task = task.take();
task.unwrap().detach();
}
#[ cfg( feature = "async_std" ) ] InnerJh::AsyncStd{ ref detached, .. } =>
{
detached.store( true, Ordering::Relaxed );
}
InnerJh::RemoteHandle( handle ) =>
{
if let Some(rh) = handle.take() { rh.forget() };
}
}
}
}
impl<T: 'static> Future for JoinHandle<T>
{
type Output = T;
fn poll( self: Pin<&mut Self>, cx: &mut Context<'_> ) -> Poll<Self::Output>
{
match &mut self.get_mut().inner
{
#[ cfg(any( feature = "tokio_tp", feature = "tokio_ct" )) ]
InnerJh::Tokio{ handle, .. } =>
{
match ready!( Pin::new( handle ).poll( cx ) )
{
Ok (t) => Poll::Ready( t ),
Err(e) =>
{
panic!( "Task has been canceled. Are you dropping the executor to early? Error: {}", e );
}
}
}
#[ cfg( feature = "async_std" ) ] InnerJh::AsyncStd{ handle, .. } =>
{
match ready!( Pin::new( handle ).poll( cx ) )
{
Ok (t) => Poll::Ready( t ),
Err(_) => unreachable!(),
}
}
#[ cfg( feature = "async_global" ) ] InnerJh::AsyncGlobal{ task, .. } =>
{
Pin::new( task.as_mut().unwrap() ).poll( cx )
}
InnerJh::RemoteHandle( ref mut handle ) => Pin::new( handle ).as_pin_mut().expect( "no polling after detach" ).poll( cx ),
}
}
}
impl<T> Drop for JoinHandle<T>
{
fn drop( &mut self )
{
match &mut self.inner
{
#[ cfg(any( feature = "tokio_tp", feature = "tokio_ct" )) ]
InnerJh::Tokio{ handle, detached, .. } =>
if !detached.load( Ordering::Relaxed ) { handle.abort() },
#[ cfg( feature = "async_std" ) ] InnerJh::AsyncStd { a_handle, detached, .. } =>
if !detached.load( Ordering::Relaxed ) { a_handle.abort() },
#[ cfg( feature = "async_global" ) ] InnerJh::AsyncGlobal { .. } => {}
InnerJh::RemoteHandle( _ ) => {},
};
}
}