use std::cell::UnsafeCell;
use std::marker::PhantomData;
use lock_api::RawRwLock;
use crate::poisonable::PoisonFlag;
use crate::ThreadKey;
mod rwlock;
mod read_guard;
mod write_guard;
#[cfg(feature = "spin")]
pub type SpinRwLock<T> = RwLock<T, spin::RwLock<()>>;
#[cfg(feature = "parking_lot")]
pub type ParkingRwLock<T> = RwLock<T, parking_lot::RawRwLock>;
pub struct RwLock<T: ?Sized, R> {
raw: R,
poison: PoisonFlag,
data: UnsafeCell<T>,
}
pub struct RwLockReadRef<'a, T: ?Sized, R: RawRwLock>(
&'a RwLock<T, R>,
PhantomData<R::GuardMarker>,
);
pub struct RwLockWriteRef<'a, T: ?Sized, R: RawRwLock>(
&'a RwLock<T, R>,
PhantomData<R::GuardMarker>,
);
pub struct RwLockReadGuard<'a, T: ?Sized, R: RawRwLock> {
rwlock: RwLockReadRef<'a, T, R>,
thread_key: ThreadKey,
}
pub struct RwLockWriteGuard<'a, T: ?Sized, R: RawRwLock> {
rwlock: RwLockWriteRef<'a, T, R>,
thread_key: ThreadKey,
}
#[cfg(test)]
mod tests {
use crate::LockCollection;
use crate::RwLock;
use crate::ThreadKey;
#[test]
fn unlocked_when_initialized() {
let key = ThreadKey::get().unwrap();
let lock: crate::RwLock<_> = RwLock::new("Hello, world!");
assert!(!lock.is_locked());
assert!(lock.try_write(key).is_ok());
}
#[test]
fn locked_after_read() {
let key = ThreadKey::get().unwrap();
let lock: crate::RwLock<_> = RwLock::new("Hello, world!");
let guard = lock.read(key);
assert!(lock.is_locked());
drop(guard)
}
#[test]
fn locked_after_write() {
let key = ThreadKey::get().unwrap();
let lock: crate::RwLock<_> = RwLock::new("Hello, world!");
let guard = lock.write(key);
assert!(lock.is_locked());
drop(guard)
}
#[test]
fn locked_after_scoped_write() {
let mut key = ThreadKey::get().unwrap();
let lock = crate::RwLock::new("Hello, world!");
lock.scoped_write(&mut key, |guard| {
assert!(lock.is_locked());
assert_eq!(*guard, "Hello, world!");
std::thread::scope(|s| {
s.spawn(|| {
let key = ThreadKey::get().unwrap();
assert!(lock.try_read(key).is_err());
});
})
})
}
#[test]
fn get_mut_works() {
let key = ThreadKey::get().unwrap();
let mut lock = crate::RwLock::from(42);
let mut_ref = lock.get_mut();
*mut_ref = 24;
lock.scoped_read(key, |guard| assert_eq!(*guard, 24))
}
#[test]
fn try_write_can_fail() {
let key = ThreadKey::get().unwrap();
let lock = crate::RwLock::new("Hello");
let guard = lock.write(key);
std::thread::scope(|s| {
s.spawn(|| {
let key = ThreadKey::get().unwrap();
let r = lock.try_write(key);
assert!(r.is_err());
});
});
drop(guard);
}
#[test]
fn try_read_can_fail() {
let key = ThreadKey::get().unwrap();
let lock = crate::RwLock::new("Hello");
let guard = lock.write(key);
std::thread::scope(|s| {
s.spawn(|| {
let key = ThreadKey::get().unwrap();
let r = lock.try_read(key);
assert!(r.is_err());
});
});
drop(guard);
}
#[test]
fn read_display_works() {
let key = ThreadKey::get().unwrap();
let lock: crate::RwLock<_> = RwLock::new("Hello, world!");
let guard = lock.read(key);
assert_eq!(guard.to_string(), "Hello, world!".to_string());
}
#[test]
fn write_display_works() {
let key = ThreadKey::get().unwrap();
let lock: crate::RwLock<_> = RwLock::new("Hello, world!");
let guard = lock.write(key);
assert_eq!(guard.to_string(), "Hello, world!".to_string());
}
#[test]
fn read_ref_display_works() {
let lock: crate::RwLock<_> = RwLock::new("Hello, world!");
let guard = unsafe { lock.try_read_no_key().unwrap() };
assert_eq!(guard.to_string(), "Hello, world!".to_string());
}
#[test]
fn write_ref_display_works() {
let lock: crate::RwLock<_> = RwLock::new("Hello, world!");
let guard = unsafe { lock.try_write_no_key().unwrap() };
assert_eq!(guard.to_string(), "Hello, world!".to_string());
}
#[test]
fn dropping_read_ref_releases_rwlock() {
let lock: crate::RwLock<_> = RwLock::new("Hello, world!");
let guard = unsafe { lock.try_read_no_key().unwrap() };
drop(guard);
assert!(!lock.is_locked());
}
#[test]
fn dropping_write_guard_releases_rwlock() {
let key = ThreadKey::get().unwrap();
let lock: crate::RwLock<_> = RwLock::new("Hello, world!");
let guard = lock.write(key);
drop(guard);
assert!(!lock.is_locked());
}
#[test]
fn unlock_write() {
let key = ThreadKey::get().unwrap();
let lock = crate::RwLock::new("Hello, world");
let mut guard = lock.write(key);
*guard = "Goodbye, world!";
let key = RwLock::unlock_write(guard);
let guard = lock.read(key);
assert_eq!(*guard, "Goodbye, world!");
}
#[test]
fn unlock_read() {
let key = ThreadKey::get().unwrap();
let lock = crate::RwLock::new("Hello, world");
let guard = lock.read(key);
assert_eq!(*guard, "Hello, world");
let key = RwLock::unlock_read(guard);
let guard = lock.write(key);
assert_eq!(*guard, "Hello, world");
}
#[test]
fn read_ref_as_ref() {
let key = ThreadKey::get().unwrap();
let lock = LockCollection::new(crate::RwLock::new("hi"));
let guard = lock.read(key);
assert_eq!(*(*guard).as_ref(), "hi");
}
#[test]
fn read_guard_as_ref() {
let key = ThreadKey::get().unwrap();
let lock = crate::RwLock::new("hi");
let guard = lock.read(key);
assert_eq!(*guard.as_ref(), "hi");
}
#[test]
fn write_ref_as_ref() {
let key = ThreadKey::get().unwrap();
let lock = LockCollection::new(crate::RwLock::new("hi"));
let guard = lock.lock(key);
assert_eq!(*(*guard).as_ref(), "hi");
}
#[test]
fn write_guard_as_ref() {
let key = ThreadKey::get().unwrap();
let lock = crate::RwLock::new("hi");
let guard = lock.write(key);
assert_eq!(*guard.as_ref(), "hi");
}
#[test]
fn write_guard_as_mut() {
let key = ThreadKey::get().unwrap();
let lock = crate::RwLock::new("hi");
let mut guard = lock.write(key);
assert_eq!(*guard.as_mut(), "hi");
*guard.as_mut() = "foo";
assert_eq!(*guard.as_mut(), "foo");
}
}