use std::task::{Context, Poll, ready};
use std::time::{Duration, Instant};
use std::{fmt, future::Future, pin::Pin};
use async_channel::Sender;
use crate::arbiter::{Arbiter, ArbiterCommand};
#[inline]
pub fn now() -> Instant {
Instant::now()
}
#[inline]
pub fn spawn<F>(f: F) -> JoinHandle<F::Output>
where
F: Future + 'static,
{
let task = tok_io::task::spawn_local(crate::task::wrap(f));
JoinHandle {
task: Some(Either::Task(task)),
}
}
#[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)]
enum Either<T> {
Task(tok_io::task::JoinHandle<T>),
Spawn(crate::task::RemoteJoin<T>),
}
#[derive(Debug)]
pub struct JoinHandle<T> {
task: Option<Either<T>>,
}
impl<T> JoinHandle<T> {
pub fn cancel(mut self) {
match self.task.take() {
Some(Either::Task(fut)) => fut.abort(),
Some(Either::Spawn(fut)) => fut.cancel(),
None => (),
}
}
pub fn detach(mut self) {
self.task.take();
}
pub fn is_finished(&self) -> bool {
match &self.task {
Some(Either::Task(fut)) => fut.is_finished(),
Some(Either::Spawn(fut)) => fut.is_finished(),
None => true,
}
}
}
impl<T> Drop for JoinHandle<T> {
fn drop(&mut self) {
self.task.take();
}
}
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(Either::Task(fut)) => ready!(Pin::new(fut).poll(cx)).map_err(|_| JoinError),
Some(Either::Spawn(fut)) => ready!(Pin::new(fut).poll(cx)).map_err(|_| JoinError),
None => Err(JoinError),
})
}
}
#[derive(Clone, Debug)]
pub struct Handle {
sender: Sender<ArbiterCommand>,
rt: Option<tok_io::runtime::Handle>,
}
impl Handle {
pub(crate) fn new(sender: Sender<ArbiterCommand>) -> Self {
let rt = tok_io::runtime::Handle::try_current()
.ok()
.filter(|h| h.runtime_flavor() == tok_io::runtime::RuntimeFlavor::CurrentThread);
Self { sender, 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<crate::Histogram> {
None
}
pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
where
F: Future + Send + 'static,
F::Output: Send + 'static,
{
JoinHandle {
task: Some(Either::Spawn(crate::task::RemoteJoin::spawn(
&self.sender,
future,
))),
}
}
pub fn spawn_detached<F>(&self, future: F)
where
F: Future + Send + 'static,
{
let _ = self
.sender
.try_send(ArbiterCommand::Execute(Box::pin(async move {
future.await;
})));
}
}