use std::future::Future;
#[cfg(not(target_arch = "wasm32"))]
pub use tokio_runtime::*;
#[cfg(target_arch = "wasm32")]
pub use wasm_runtime::*;
#[cfg(not(target_arch = "wasm32"))]
pub fn spawn<F>(future: F)
where
F: Future + Send + 'static,
F::Output: Send + 'static,
{
tokio::spawn(future);
}
#[cfg(target_arch = "wasm32")]
pub fn spawn<F>(future: F)
where
F: Future + 'static,
F::Output: 'static,
{
wasm_bindgen_futures::spawn_local(async move {
future.await;
});
}
pub async fn sleep(duration: std::time::Duration) {
#[cfg(not(target_arch = "wasm32"))]
{
tokio::time::sleep(duration).await;
}
#[cfg(target_arch = "wasm32")]
{
use wasm_bindgen_futures::JsFuture;
use web_sys::Window;
let promise = js_sys::Promise::new(&mut |resolve, _| {
let window: Window = web_sys::window().expect("no window");
window
.set_timeout_with_callback_and_timeout_and_arguments_0(
&resolve,
duration.as_millis() as i32,
)
.expect("setTimeout failed");
});
JsFuture::from(promise).await.ok();
}
}
#[cfg(not(target_arch = "wasm32"))]
pub type Mutex<T> = tokio::sync::Mutex<T>;
#[cfg(target_arch = "wasm32")]
pub type Mutex<T> = futures::lock::Mutex<T>;
#[cfg(not(target_arch = "wasm32"))]
pub use tokio_runtime::RwLock;
#[cfg(target_arch = "wasm32")]
pub use wasm_runtime::RwLock;
#[cfg(not(target_arch = "wasm32"))]
pub use tokio::sync::oneshot;
#[cfg(target_arch = "wasm32")]
pub use futures::channel::oneshot;
#[cfg(not(target_arch = "wasm32"))]
pub use tokio::sync::mpsc;
#[cfg(target_arch = "wasm32")]
pub use futures::channel::mpsc;
#[cfg(not(target_arch = "wasm32"))]
mod tokio_runtime {
use super::Future;
pub use tokio::sync::RwLock;
pub type JoinHandle<T> = tokio::task::JoinHandle<T>;
pub fn block_on<F: Future>(future: F) -> F::Output {
tokio::runtime::Runtime::new()
.expect("Failed to create runtime")
.block_on(future)
}
}
#[cfg(target_arch = "wasm32")]
mod wasm_runtime {
use super::Future;
use futures::lock::{Mutex, MutexGuard};
use std::ops::{Deref, DerefMut};
use std::pin::Pin;
use std::task::{Context, Poll};
pub struct RwLock<T> {
inner: Mutex<T>,
}
impl<T> RwLock<T> {
pub fn new(value: T) -> Self {
Self {
inner: Mutex::new(value),
}
}
pub async fn read(&self) -> RwLockReadGuard<'_, T> {
RwLockReadGuard {
guard: self.inner.lock().await,
}
}
pub async fn write(&self) -> RwLockWriteGuard<'_, T> {
RwLockWriteGuard {
guard: self.inner.lock().await,
}
}
}
pub struct RwLockReadGuard<'a, T> {
guard: MutexGuard<'a, T>,
}
impl<T> Deref for RwLockReadGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&*self.guard
}
}
pub struct RwLockWriteGuard<'a, T> {
guard: MutexGuard<'a, T>,
}
impl<T> Deref for RwLockWriteGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&*self.guard
}
}
impl<T> DerefMut for RwLockWriteGuard<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut *self.guard
}
}
pub struct JoinHandle<T> {
_phantom: std::marker::PhantomData<T>,
}
impl<T> Future for JoinHandle<T> {
type Output = Result<T, JoinError>;
fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> {
Poll::Pending
}
}
#[derive(Debug)]
pub struct JoinError;
impl std::fmt::Display for JoinError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Task joining not supported in WASM")
}
}
impl std::error::Error for JoinError {}
}