xutex 0.2.1

an extremely fast async mutex with alternative sync API
Documentation
use super::*;
use std::sync::Arc;
use std::thread;

#[test]
fn test_mutex_new() {
    let mutex = Mutex::new(42);
    assert_eq!(*mutex.lock(), 42);
}

#[test]
fn test_mutex_lock_unlock() {
    let mutex = Mutex::new(0);
    {
        let mut guard = mutex.lock();
        *guard = 10;
    }
    assert_eq!(*mutex.lock(), 10);
}

#[test]
fn test_mutex_try_lock_success() {
    let mutex = Mutex::new(5);
    let guard = mutex.try_lock();
    assert!(guard.is_some());
    assert_eq!(*guard.unwrap(), 5);
}

#[test]
fn test_mutex_try_lock_fail() {
    let mutex = Mutex::new(5);
    let _guard = mutex.lock();
    assert!(mutex.try_lock().is_none());
}

#[cfg(miri)]
const THREAD_COUNT: usize = 16;
#[cfg(not(miri))]
const THREAD_COUNT: usize = 128;
#[cfg(miri)]
const INCREMENTS_PER_THREAD: usize = 32;
#[cfg(not(miri))]
const INCREMENTS_PER_THREAD: usize = 1024 * 10;

#[test]
fn test_mutex_multithreaded() {
    let mutex = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    for _ in 0..THREAD_COUNT {
        let mutex_clone = Arc::clone(&mutex);
        let handle = thread::spawn(move || {
            for _ in 0..INCREMENTS_PER_THREAD {
                let mut guard = mutex_clone.lock();
                *guard += 1;
            }
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().unwrap();
    }

    assert_eq!(*mutex.lock(), THREAD_COUNT * INCREMENTS_PER_THREAD);
}

#[test]
fn test_tokio_multicoroutine() {
    use tokio::runtime::Builder;

    let rt = Builder::new_multi_thread()
        .worker_threads(
            std::thread::available_parallelism()
                .map(|n| n.get())
                .unwrap_or(4),
        )
        .enable_all()
        .build()
        .unwrap();
    let mutex = Arc::new(AsyncMutex::new(0));

    rt.block_on(async {
        let mut handles = vec![];
        for _ in 0..THREAD_COUNT {
            let mutex_clone = Arc::clone(&mutex);
            let handle = tokio::spawn(async move {
                for _ in 0..INCREMENTS_PER_THREAD {
                    let mut guard = mutex_clone.lock().await;
                    *guard += 1;
                }
            });
            handles.push(handle);
        }

        for handle in handles {
            handle.await.unwrap();
        }
    });

    rt.block_on(async {
        assert_eq!(*mutex.lock().await, THREAD_COUNT * INCREMENTS_PER_THREAD);
    });
}

#[test]
fn test_mutex_multiple_locks() {
    let mutex = Mutex::new(0);
    for i in 1..=10 {
        let mut guard = mutex.lock();
        *guard += i;
    }
    assert_eq!(*mutex.lock(), 55);
}

#[test]
fn test_mutex_as_async_conversion() {
    let mutex = Mutex::new(100);
    let async_ref = mutex.as_async();
    assert_eq!(*async_ref.try_lock().unwrap(), 100);
}

#[test]
fn test_async_mutex_as_sync_conversion() {
    let async_mutex = AsyncMutex::new(200);
    let sync_ref = async_mutex.as_sync();
    assert_eq!(*sync_ref.try_lock().unwrap(), 200);
}