use std::future::Future;
#[cfg(all(feature = "realtime", not(target_arch = "wasm32")))]
#[async_trait::async_trait]
pub trait AsyncLock<T>: Send + Sync {
type Guard<'a>: std::ops::Deref<Target = T> + Send
where
T: 'a,
Self: 'a;
type GuardMut<'a>: std::ops::DerefMut<Target = T> + Send
where
T: 'a,
Self: 'a;
async fn read(&self) -> Self::Guard<'_>;
async fn write(&self) -> Self::GuardMut<'_>;
}
#[cfg(all(feature = "realtime", target_arch = "wasm32"))]
#[async_trait::async_trait(?Send)]
pub trait AsyncLock<T> {
type Guard<'a>: std::ops::Deref<Target = T>
where
T: 'a,
Self: 'a;
type GuardMut<'a>: std::ops::DerefMut<Target = T>
where
T: 'a,
Self: 'a;
async fn read(&self) -> Self::Guard<'_>;
async fn write(&self) -> Self::GuardMut<'_>;
}
#[cfg(all(feature = "realtime", not(target_arch = "wasm32")))]
pub struct TokioRwLock<T>(tokio::sync::RwLock<T>);
#[cfg(all(feature = "realtime", not(target_arch = "wasm32")))]
impl<T> TokioRwLock<T> {
pub fn new(value: T) -> Self {
Self(tokio::sync::RwLock::new(value))
}
}
#[cfg(all(feature = "realtime", not(target_arch = "wasm32")))]
#[async_trait::async_trait]
impl<T: Send + Sync> AsyncLock<T> for TokioRwLock<T> {
type Guard<'a>
= tokio::sync::RwLockReadGuard<'a, T>
where
T: 'a;
type GuardMut<'a>
= tokio::sync::RwLockWriteGuard<'a, T>
where
T: 'a;
async fn read(&self) -> Self::Guard<'_> {
self.0.read().await
}
async fn write(&self) -> Self::GuardMut<'_> {
self.0.write().await
}
}
#[cfg(all(feature = "realtime", target_arch = "wasm32"))]
pub struct WasmRwLock<T> {
inner: futures_util::lock::Mutex<T>,
}
#[cfg(all(feature = "realtime", target_arch = "wasm32"))]
impl<T> WasmRwLock<T> {
pub fn new(value: T) -> Self {
Self {
inner: futures_util::lock::Mutex::new(value),
}
}
}
#[cfg(all(feature = "realtime", target_arch = "wasm32"))]
pub struct WasmReadGuard<'a, T>(futures_util::lock::MutexGuard<'a, T>);
#[cfg(all(feature = "realtime", target_arch = "wasm32"))]
impl<'a, T> std::ops::Deref for WasmReadGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&*self.0
}
}
#[cfg(all(feature = "realtime", target_arch = "wasm32"))]
pub struct WasmWriteGuard<'a, T>(futures_util::lock::MutexGuard<'a, T>);
#[cfg(all(feature = "realtime", target_arch = "wasm32"))]
impl<'a, T> std::ops::Deref for WasmWriteGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&*self.0
}
}
#[cfg(all(feature = "realtime", target_arch = "wasm32"))]
impl<'a, T> std::ops::DerefMut for WasmWriteGuard<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut *self.0
}
}
#[cfg(all(feature = "realtime", target_arch = "wasm32"))]
#[async_trait::async_trait(?Send)]
impl<T> AsyncLock<T> for WasmRwLock<T> {
type Guard<'a>
= WasmReadGuard<'a, T>
where
T: 'a;
type GuardMut<'a>
= WasmWriteGuard<'a, T>
where
T: 'a;
async fn read(&self) -> Self::Guard<'_> {
WasmReadGuard(self.inner.lock().await)
}
async fn write(&self) -> Self::GuardMut<'_> {
WasmWriteGuard(self.inner.lock().await)
}
}
#[cfg(all(feature = "realtime", not(target_arch = "wasm32")))]
pub type RuntimeLock<T> = TokioRwLock<T>;
#[cfg(all(feature = "realtime", target_arch = "wasm32"))]
pub type RuntimeLock<T> = WasmRwLock<T>;
#[cfg(all(feature = "realtime", not(target_arch = "wasm32")))]
#[allow(dead_code)]
pub fn spawn_task<F>(future: F) -> tokio::task::JoinHandle<F::Output>
where
F: Future + Send + 'static,
F::Output: Send + 'static,
{
tokio::spawn(future)
}
#[cfg(all(feature = "realtime", target_arch = "wasm32"))]
#[allow(dead_code)]
pub fn spawn_task<F>(future: F)
where
F: Future<Output = ()> + 'static,
{
wasm_bindgen_futures::spawn_local(future);
}