maitake-sync 0.2.2

No-std async synchronization primitives from Maitake
Documentation
use super::*;
use crate::loom::{self, future, sync::Arc, thread};

#[test]
fn write() {
    const WRITERS: usize = 2;

    loom::model(|| {
        let lock = Arc::new(RwLock::<usize>::new(0));
        let threads = (0..WRITERS)
            .map(|_| {
                let lock = lock.clone();
                thread::spawn(writer(lock))
            })
            .collect::<Vec<_>>();

        for thread in threads {
            thread.join().expect("writer thread mustn't panic");
        }

        let guard = future::block_on(lock.read());
        assert_eq!(*guard, WRITERS, "final state must equal number of writers");
    });
}

#[test]
fn read_write() {
    const WRITERS: usize = 2;

    loom::model(|| {
        let lock = Arc::new(RwLock::<usize>::new(0));
        let w_threads = (0..WRITERS)
            .map(|_| {
                let lock = lock.clone();
                thread::spawn(writer(lock))
            })
            .collect::<Vec<_>>();

        {
            let guard = future::block_on(lock.read());
            assert!(*guard == 0 || *guard == 1 || *guard == 2);
        }

        for thread in w_threads {
            thread.join().expect("writer thread mustn't panic")
        }

        let guard = future::block_on(lock.read());
        assert_eq!(*guard, WRITERS, "final state must equal number of writers");
    });
}

fn writer(lock: Arc<RwLock<usize>>) -> impl FnOnce() {
    move || {
        future::block_on(async {
            let mut guard = lock.write().await;
            *guard += 1;
        })
    }
}

#[test]
#[cfg(feature = "alloc")]
fn write_owned() {
    const WRITERS: usize = 2;

    loom::model(|| {
        let lock = alloc::sync::Arc::new(RwLock::<usize>::new(0));
        let threads = (0..WRITERS)
            .map(|_| {
                let lock = lock.clone();
                thread::spawn(owned_writer(lock))
            })
            .collect::<Vec<_>>();

        for thread in threads {
            thread.join().expect("writer thread mustn't panic");
        }

        let guard = future::block_on(lock.read());
        assert_eq!(*guard, WRITERS, "final state must equal number of writers");
    });
}

#[test]
#[cfg(feature = "alloc")]
fn read_write_owned() {
    const WRITERS: usize = 2;

    loom::model(|| {
        let lock = alloc::sync::Arc::new(RwLock::<usize>::new(0));
        let w_threads = (0..WRITERS)
            .map(|_| {
                let lock = lock.clone();
                thread::spawn(owned_writer(lock))
            })
            .collect::<Vec<_>>();

        {
            let guard = future::block_on(lock.read_owned());
            assert!(*guard == 0 || *guard == 1 || *guard == 2);
        }

        for thread in w_threads {
            thread.join().expect("writer thread mustn't panic")
        }

        let guard = future::block_on(lock.read_owned());
        assert_eq!(*guard, WRITERS, "final state must equal number of writers");
    });
}

#[cfg(feature = "alloc")]
fn owned_writer(lock: alloc::sync::Arc<RwLock<usize>>) -> impl FnOnce() {
    move || {
        future::block_on(async {
            let mut guard = lock.write_owned().await;
            *guard += 1;
        })
    }
}