async_executors
async_executors copied to clipboard
Support runtime sync primitives, RwLock and Mutex
Would be nice to support the sync primitives too, async_std and tokio have their own sync primitives, I created a trait for abstract their behavior, also fallback to rust-std in case the runtime doesn't support custom sync primitives, this add extra overhead of course:
traits
pub trait RwLockT<T: Send + Sync>: RwLockConstructorT {
type ReadGuard<'a>: Deref<Target = T> where Self: 'a, T: 'a;
type ReadFuture<'a>: Future<Output = Self::ReadGuard<'a>> where Self: 'a, T: 'a;
type WriteGuard<'a>: DerefMut<Target = T> where Self: 'a, T: 'a;
type WriteFuture<'a>: Future<Output = Self::WriteGuard<'a>> where Self: 'a, T: 'a;
fn read(&self) -> Self::ReadFuture<'_>;
fn write(&self) -> Self::WriteFuture<'_>;
}
pub trait RwLockConstructorT {
type RwLock<T>: RwLockT<T> where T: Send + Sync;
fn new<T>(value: T) -> Self::RwLock<T> where T: Send + Sync;
}
rust std:
struct StdRwLock<T>(std::sync::RwLock<T>);
impl <E> RwLockConstructorT for StdRwLock<E> {
type RwLock<T> = StdRwLock<T> where T: Send + Sync;
fn new<T>(value: T) -> Self::RwLock<T> where T: Send + Sync {
StdRwLock(std::sync::RwLock::new(value))
}
}
impl<T> RwLockT<T> for StdRwLock<T> where T: Send + Sync,
{
type ReadGuard<'a> = std::sync::RwLockReadGuard<'a, T> where T: 'a;
type ReadFuture<'a> = futures_util::future::Ready<Self::ReadGuard<'a>> where T: 'a;
type WriteGuard<'a> = std::sync::RwLockWriteGuard<'a, T> where T: 'a;
type WriteFuture<'a> = futures_util::future::Ready<Self::WriteGuard<'a>> where T: 'a;
fn read(&self) -> Self::ReadFuture<'_> {
futures_util::future::ready(self.0.read().expect("not poisoned; qed"))
}
fn write(&self) -> Self::WriteFuture<'_> {
futures_util::future::ready(self.0.write().expect("not poisoned; qed"))
}
}
tokio:
struct TokioRwLock<T>(tokio::sync::RwLock<T>);
impl <E> RwLockConstructorT for TokioRwLock<E> {
type RwLock<T> = TokioRwLock<T> where T: Send + Sync;
fn new<T>(value: T) -> Self::RwLock<T> where T: Send + Sync {
TokioRwLock(tokio::sync::RwLock::new(value))
}
}
impl<T> RwLockT<T> for TokioRwLock<T> where T: Send + Sync,
{
type ReadGuard<'a> = tokio::sync::RwLockReadGuard<'a, T> where T: 'a;
type ReadFuture<'a> = BoxFuture<'a, Self::ReadGuard<'a>> where T: 'a;
type WriteGuard<'a> = tokio::sync::RwLockWriteGuard<'a, T> where T: 'a;
type WriteFuture<'a> = BoxFuture<'a, Self::WriteGuard<'a>> where T: 'a;
fn read(&self) -> Self::ReadFuture<'_> {
self.0.read().boxed()
}
fn write(&self) -> Self::WriteFuture<'_> {
self.0.write().boxed()
}
}
async-std:
struct AsyncStdRwLock<T>(async_std::sync::RwLock<T>);
impl <E> RwLockConstructorT for AsyncStdRwLock<E> {
type RwLock<T> = AsyncStdRwLock<T> where T: Send + Sync;
fn new<T>(value: T) -> Self::RwLock<T> where T: Send + Sync {
AsyncStdRwLock(async_std::sync::RwLock::new(value))
}
}
impl<T> RwLockT<T> for AsyncStdRwLock<T> where T: Send + Sync,
{
type ReadGuard<'a> = async_std::sync::RwLockReadGuard<'a, T> where T: 'a;
type ReadFuture<'a> = BoxFuture<'a, Self::ReadGuard<'a>> where T: 'a;
type WriteGuard<'a> = async_std::sync::RwLockWriteGuard<'a, T> where T: 'a;
type WriteFuture<'a> = BoxFuture<'a, Self::WriteGuard<'a>> where T: 'a;
fn read(&self) -> Self::ReadFuture<'_> {
self.0.read().boxed()
}
fn write(&self) -> Self::WriteFuture<'_> {
self.0.write().boxed()
}
}
usage:
async fn lock_unlock_test<T: RwLockConstructorT>() {
let rwlock = T::new(1234);
{
*rwlock.write().await.deref_mut() += 1;
}
let result = rwlock.read().await;
println!("value: {:?}", name, result.deref());
}
#[tokio::main]
async fn main() {
lock_unlock_test::<StdRwLock<()>>().await;
lock_unlock_test::<TokioRwLock<()>>().await;
lock_unlock_test::<AsyncStdRwLock<()>>().await;
}