use std::task::{Context, Poll, ready};
use std::time::{Duration, Instant};
use std::{fmt, future::Future, marker::PhantomData, pin::Pin, rc::Rc, sync::Arc};
use crate::arbiter::Arbiter;
use crate::metrics::Histogram;
use crate::remote::{Job, RemoteJoin, Spawner};
#[inline]
pub fn now() -> Instant {
Instant::now()
}
#[inline]
pub fn spawn<F>(f: F) -> JoinHandle<F::Output>
where
F: Future + 'static,
{
JoinHandle::new(tok_io::task::spawn_local(crate::task::wrap(f)))
}
#[inline]
pub fn spawn_detached<F>(f: F)
where
F: Future + 'static,
{
drop(tok_io::task::spawn_local(crate::task::wrap(f)));
}
#[derive(Debug, Copy, Clone)]
pub struct JoinError;
impl fmt::Display for JoinError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "JoinError")
}
}
impl std::error::Error for JoinError {}
#[derive(Debug)]
pub struct JoinHandle<T> {
task: Option<tok_io::task::JoinHandle<T>>,
cancel_on_drop: bool,
_local: PhantomData<Rc<()>>,
}
impl<T> JoinHandle<T> {
fn new(task: tok_io::task::JoinHandle<T>) -> Self {
Self {
task: Some(task),
cancel_on_drop: false,
_local: PhantomData,
}
}
#[must_use]
pub fn cancel_on_drop(mut self) -> Self {
self.cancel_on_drop = true;
self
}
pub fn cancel(mut self) {
if let Some(t) = self.task.take() {
t.abort();
}
}
#[deprecated(
since = "4.5.0",
note = "Drop the handle instead if cancel_on_drop() is not enabled"
)]
pub fn detach(mut self) {
self.cancel_on_drop = false;
}
pub fn is_finished(&self) -> bool {
match &self.task {
Some(t) => t.is_finished(),
None => true,
}
}
}
impl<T> Drop for JoinHandle<T> {
fn drop(&mut self) {
if self.cancel_on_drop
&& let Some(t) = &self.task
{
t.abort();
}
}
}
impl<T> Future for JoinHandle<T> {
type Output = Result<T, JoinError>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
Poll::Ready(match self.task.as_mut() {
Some(t) => ready!(Pin::new(t).poll(cx)).map_err(|_| JoinError),
None => Err(JoinError),
})
}
}
#[derive(Debug)]
pub struct RemoteJoinHandle<T> {
inner: Inner<T>,
}
#[derive(Debug)]
enum Inner<T> {
Local(JoinHandle<T>),
Remote(RemoteJoin<T>),
}
impl<T> RemoteJoinHandle<T> {
fn local(task: JoinHandle<T>) -> Self {
Self {
inner: Inner::Local(task),
}
}
fn remote(join: RemoteJoin<T>) -> Self {
Self {
inner: Inner::Remote(join),
}
}
pub fn cancel(self) {
match self.inner {
Inner::Local(t) => t.cancel(),
Inner::Remote(t) => t.cancel(),
}
}
#[deprecated(since = "4.5.0", note = "Use drop(handle) instead")]
pub fn detach(self) {}
pub fn is_finished(&self) -> bool {
match &self.inner {
Inner::Local(t) => t.is_finished(),
Inner::Remote(t) => t.is_finished(),
}
}
}
impl<T> Future for RemoteJoinHandle<T> {
type Output = Result<T, JoinError>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
Poll::Ready(match &mut self.inner {
Inner::Local(t) => ready!(Pin::new(t).poll(cx)),
Inner::Remote(t) => ready!(t.poll_join(cx)).ok_or(JoinError),
})
}
}
#[derive(Clone, Debug)]
pub struct Handle {
spawner: Arc<Spawner>,
rt: Option<tok_io::runtime::Handle>,
}
impl Handle {
pub(crate) fn new() -> Self {
let rt = tok_io::runtime::Handle::try_current()
.ok()
.filter(|h| h.runtime_flavor() == tok_io::runtime::RuntimeFlavor::CurrentThread);
Self {
spawner: Spawner::start(),
rt,
}
}
pub fn current() -> Self {
Arbiter::current().handle().clone()
}
#[inline]
pub fn notify(&self) {}
pub fn busy_duration(&self) -> Option<Duration> {
self.rt
.as_ref()
.map(|h| h.metrics().worker_total_busy_duration(0))
}
pub fn current_turn(&self) -> Option<Duration> {
None
}
pub fn poll_count(&self) -> Option<u64> {
None
}
pub fn poll_again_count(&self) -> Option<u64> {
None
}
pub fn self_wake_count(&self) -> Option<u64> {
None
}
pub fn current_task(&self) -> Option<&'static std::panic::Location<'static>> {
None
}
pub fn poll_histogram(&self) -> Option<Histogram> {
None
}
pub fn spawn<F>(&self, future: F) -> RemoteJoinHandle<F::Output>
where
F: Future + Send + 'static,
F::Output: Send + 'static,
{
if self.spawner.is_owner() {
RemoteJoinHandle::local(spawn(future))
} else {
let job = Job::new(future, true);
let join = RemoteJoin::new(job.clone());
self.spawner.submit(job);
RemoteJoinHandle::remote(join)
}
}
pub fn spawn_detached<F>(&self, future: F)
where
F: Future + Send + 'static,
{
if self.spawner.is_owner() {
spawn_detached(future);
} else {
self.spawner.submit(Job::new(
async move {
future.await;
},
false,
));
}
}
}