use core::{pin::Pin, time::Duration};
#[cfg(not(target_arch = "wasm32"))]
pub use std::time::Instant;
use std::{
error::Error,
future::Future,
ops::{Deref, DerefMut},
sync::Arc,
time::SystemTime,
};
use async_lock::{
Mutex as AsyncMutex, MutexGuard as AsyncMutexGuard, RwLock as AsyncRwLock, RwLockReadGuard,
RwLockWriteGuard,
};
use fusio_core::{MaybeSend, MaybeSendFuture, MaybeSync};
#[cfg(not(target_arch = "wasm32"))]
use futures_executor::block_on;
#[cfg(all(target_arch = "wasm32", feature = "executor-web"))]
use js_sys::Date;
#[cfg(target_arch = "wasm32")]
pub use web_time::Instant;
pub trait JoinHandle<R> {
fn join(self) -> impl Future<Output = Result<R, Box<dyn Error + Send + Sync>>> + MaybeSend;
}
pub trait Mutex<T> {
type Guard<'a>: DerefMut<Target = T> + MaybeSend + 'a
where
Self: 'a;
fn lock(&self) -> impl Future<Output = Self::Guard<'_>> + MaybeSend;
}
pub trait RwLock<T> {
type ReadGuard<'a>: Deref<Target = T> + MaybeSend + 'a
where
Self: 'a;
type WriteGuard<'a>: DerefMut<Target = T> + MaybeSend + 'a
where
Self: 'a;
fn read(&self) -> impl Future<Output = Self::ReadGuard<'_>> + MaybeSend;
fn write(&self) -> impl Future<Output = Self::WriteGuard<'_>> + MaybeSend;
}
pub trait Executor: MaybeSend + MaybeSync + 'static {
type JoinHandle<R>: JoinHandle<R> + MaybeSend
where
R: MaybeSend;
type Mutex<T>: Mutex<T> + MaybeSend + MaybeSync
where
T: MaybeSend + MaybeSync;
type RwLock<T>: RwLock<T> + MaybeSend + MaybeSync
where
T: MaybeSend + MaybeSync;
fn spawn<F>(&self, future: F) -> Self::JoinHandle<F::Output>
where
F: Future + MaybeSend + 'static,
F::Output: MaybeSend;
fn mutex<T>(value: T) -> Self::Mutex<T>
where
T: MaybeSend + MaybeSync;
fn rw_lock<T>(value: T) -> Self::RwLock<T>
where
T: MaybeSend + MaybeSync;
}
pub trait Timer: MaybeSend + MaybeSync + 'static {
fn sleep(&self, dur: Duration) -> Pin<Box<dyn MaybeSendFuture<Output = ()>>>;
fn now(&self) -> Instant;
fn system_time(&self) -> SystemTime;
}
#[cfg(all(feature = "executor-web", target_arch = "wasm32"))]
pub mod web;
#[cfg(all(feature = "opfs", target_arch = "wasm32"))]
pub mod opfs;
#[cfg(feature = "executor-tokio")]
pub mod tokio;
#[cfg(feature = "monoio")]
pub mod monoio;
#[derive(Debug, Clone)]
pub struct NoopJoinHandle<R>(Option<R>);
impl<R> JoinHandle<R> for NoopJoinHandle<R>
where
R: MaybeSend,
{
fn join(self) -> impl Future<Output = Result<R, Box<dyn Error + Send + Sync>>> + MaybeSend {
let mut value = self.0;
async move {
let out = value.take().expect("noop join handle already taken");
Ok(out)
}
}
}
#[derive(Debug)]
pub struct NoopMutex<T>(AsyncMutex<T>);
impl<T> NoopMutex<T> {
pub fn new(value: T) -> Self {
Self(AsyncMutex::new(value))
}
}
impl<T> Mutex<T> for NoopMutex<T>
where
T: MaybeSend + MaybeSync,
{
type Guard<'a>
= AsyncMutexGuard<'a, T>
where
T: 'a,
Self: 'a;
fn lock(&self) -> impl Future<Output = Self::Guard<'_>> + MaybeSend {
self.0.lock()
}
}
#[derive(Debug)]
pub struct NoopRwLock<T>(AsyncRwLock<T>);
impl<T> NoopRwLock<T> {
pub fn new(value: T) -> Self {
Self(AsyncRwLock::new(value))
}
}
impl<T> RwLock<T> for NoopRwLock<T>
where
T: MaybeSend + MaybeSync,
{
type ReadGuard<'a>
= RwLockReadGuard<'a, T>
where
T: 'a,
Self: 'a;
type WriteGuard<'a>
= RwLockWriteGuard<'a, T>
where
T: 'a,
Self: 'a;
fn read(&self) -> impl Future<Output = Self::ReadGuard<'_>> + MaybeSend {
self.0.read()
}
fn write(&self) -> impl Future<Output = Self::WriteGuard<'_>> + MaybeSend {
self.0.write()
}
}
impl<T> Timer for Arc<T>
where
T: Timer + ?Sized,
{
fn sleep(&self, dur: Duration) -> Pin<Box<dyn MaybeSendFuture<Output = ()>>> {
(**self).sleep(dur)
}
fn now(&self) -> Instant {
(**self).now()
}
fn system_time(&self) -> SystemTime {
(**self).system_time()
}
}
#[derive(Debug, Clone, Default, Copy)]
pub struct NoopExecutor;
impl Executor for NoopExecutor {
type JoinHandle<R>
= NoopJoinHandle<R>
where
R: MaybeSend;
type Mutex<T>
= NoopMutex<T>
where
T: MaybeSend + MaybeSync;
type RwLock<T>
= NoopRwLock<T>
where
T: MaybeSend + MaybeSync;
#[cfg(not(target_arch = "wasm32"))]
fn spawn<F>(&self, future: F) -> Self::JoinHandle<F::Output>
where
F: Future + MaybeSend + 'static,
F::Output: MaybeSend,
{
NoopJoinHandle(Some(block_on(future)))
}
#[cfg(target_arch = "wasm32")]
fn spawn<F>(&self, _future: F) -> Self::JoinHandle<F::Output>
where
F: Future + MaybeSend + 'static,
F::Output: MaybeSend,
{
panic!("NoopExecutor::spawn is not supported on WASM. Use WebExecutor instead.")
}
fn mutex<T>(value: T) -> Self::Mutex<T>
where
T: MaybeSend + MaybeSync,
{
NoopMutex::new(value)
}
fn rw_lock<T>(value: T) -> Self::RwLock<T>
where
T: MaybeSend + MaybeSync,
{
NoopRwLock::new(value)
}
}
impl Timer for NoopExecutor {
fn sleep(&self, _dur: Duration) -> Pin<Box<dyn MaybeSendFuture<Output = ()>>> {
Box::pin(async move {})
}
fn now(&self) -> Instant {
Instant::now()
}
#[cfg(all(target_arch = "wasm32", feature = "executor-web"))]
fn system_time(&self) -> SystemTime {
SystemTime::UNIX_EPOCH + Duration::from_millis(Date::now() as u64)
}
#[cfg(not(all(target_arch = "wasm32", feature = "executor-web")))]
fn system_time(&self) -> SystemTime {
SystemTime::now()
}
}
#[cfg(not(target_arch = "wasm32"))]
#[deprecated(since = "0.5.0", note = "Use NoopExecutor instead")]
pub type BlockingExecutor = NoopExecutor;
#[cfg(not(target_arch = "wasm32"))]
#[deprecated(since = "0.5.0", note = "Use NoopJoinHandle instead")]
pub type BlockingJoinHandle<R> = NoopJoinHandle<R>;
#[cfg(not(target_arch = "wasm32"))]
#[deprecated(since = "0.5.0", note = "Use NoopRwLock instead")]
pub type BlockingRwLock<T> = NoopRwLock<T>;
#[cfg(not(target_arch = "wasm32"))]
#[derive(Debug, Default, Clone, Copy)]
pub struct BlockingSleeper;
#[cfg(not(target_arch = "wasm32"))]
impl Timer for BlockingSleeper {
fn sleep(&self, dur: Duration) -> Pin<Box<dyn MaybeSendFuture<Output = ()>>> {
Box::pin(async move { std::thread::sleep(dur) })
}
fn now(&self) -> Instant {
Instant::now()
}
fn system_time(&self) -> SystemTime {
SystemTime::now()
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct NoopTimer;
impl Timer for NoopTimer {
fn sleep(&self, _dur: Duration) -> Pin<Box<dyn MaybeSendFuture<Output = ()>>> {
Box::pin(async move {})
}
fn now(&self) -> Instant {
Instant::now()
}
#[cfg(all(target_arch = "wasm32", feature = "executor-web"))]
fn system_time(&self) -> SystemTime {
SystemTime::UNIX_EPOCH + Duration::from_millis(Date::now() as u64)
}
#[cfg(not(all(target_arch = "wasm32", feature = "executor-web")))]
fn system_time(&self) -> SystemTime {
SystemTime::now()
}
}