async_executors icon indicating copy to clipboard operation
async_executors copied to clipboard

Support runtime sync primitives, RwLock and Mutex

Open Lohann opened this issue 1 year ago • 0 comments

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;
}

Lohann avatar Aug 27 '23 01:08 Lohann