summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/collection.rs224
-rw-r--r--src/collection/collection.rs208
-rw-r--r--src/collection/guard.rs19
-rw-r--r--src/lib.rs3
-rw-r--r--src/mutex.rs265
-rw-r--r--src/mutex/guard.rs39
-rw-r--r--src/mutex/mutex.rs208
-rw-r--r--src/mutex/mutex_ref.rs33
-rw-r--r--src/rwlock.rs376
-rw-r--r--src/rwlock/read_guard.rs52
-rw-r--r--src/rwlock/read_lock.rs60
-rw-r--r--src/rwlock/rwlock.rs163
-rw-r--r--src/rwlock/write_guard.rs69
-rw-r--r--src/rwlock/write_lock.rs60
14 files changed, 928 insertions, 851 deletions
diff --git a/src/collection.rs b/src/collection.rs
index 1ee5956..1253a0f 100644
--- a/src/collection.rs
+++ b/src/collection.rs
@@ -1,24 +1,9 @@
use std::marker::PhantomData;
-use std::ops::{Deref, DerefMut};
-use crate::{
- key::Keyable,
- lockable::{Lockable, OwnedLockable},
-};
+use crate::{key::Keyable, lockable::Lockable};
-/// returns `true` if the list contains a duplicate
-#[must_use]
-fn contains_duplicates(l: &[usize]) -> bool {
- for i in 0..l.len() {
- for j in (i + 1)..l.len() {
- if l[i] == l[j] {
- return true;
- }
- }
- }
-
- false
-}
+mod collection;
+mod guard;
/// A type which can be locked.
///
@@ -36,206 +21,3 @@ pub struct LockGuard<'a, 'key: 'a, L: Lockable<'a>, Key: Keyable + 'key> {
key: Key,
_phantom: PhantomData<&'key ()>,
}
-
-impl<'a, L: OwnedLockable<'a>> From<L> for LockCollection<L> {
- fn from(value: L) -> Self {
- Self::new(value)
- }
-}
-
-impl<'a, L: OwnedLockable<'a>> AsRef<L> for LockCollection<L> {
- fn as_ref(&self) -> &L {
- &self.collection
- }
-}
-
-impl<'a, L: OwnedLockable<'a>> AsMut<L> for LockCollection<L> {
- fn as_mut(&mut self) -> &mut L {
- &mut self.collection
- }
-}
-
-impl<'a, L: OwnedLockable<'a>> AsRef<Self> for LockCollection<L> {
- fn as_ref(&self) -> &Self {
- self
- }
-}
-
-impl<'a, L: OwnedLockable<'a>> AsMut<Self> for LockCollection<L> {
- fn as_mut(&mut self) -> &mut Self {
- self
- }
-}
-
-impl<L: IntoIterator> IntoIterator for LockCollection<L> {
- type Item = L::Item;
- type IntoIter = L::IntoIter;
-
- fn into_iter(self) -> Self::IntoIter {
- self.collection.into_iter()
- }
-}
-
-impl<'a, L> IntoIterator for &'a LockCollection<L>
-where
- &'a L: IntoIterator,
-{
- type Item = <&'a L as IntoIterator>::Item;
- type IntoIter = <&'a L as IntoIterator>::IntoIter;
-
- fn into_iter(self) -> Self::IntoIter {
- self.collection.into_iter()
- }
-}
-
-impl<'a, L> IntoIterator for &'a mut LockCollection<L>
-where
- &'a mut L: IntoIterator,
-{
- type Item = <&'a mut L as IntoIterator>::Item;
- type IntoIter = <&'a mut L as IntoIterator>::IntoIter;
-
- fn into_iter(self) -> Self::IntoIter {
- self.collection.into_iter()
- }
-}
-
-impl<'a, L: OwnedLockable<'a>, I: FromIterator<L> + OwnedLockable<'a>> FromIterator<L>
- for LockCollection<I>
-{
- fn from_iter<T: IntoIterator<Item = L>>(iter: T) -> Self {
- let iter: I = iter.into_iter().collect();
- Self::new(iter)
- }
-}
-
-impl<'a, E: OwnedLockable<'a> + Extend<L>, L: OwnedLockable<'a>> Extend<L> for LockCollection<E> {
- fn extend<T: IntoIterator<Item = L>>(&mut self, iter: T) {
- self.collection.extend(iter)
- }
-}
-
-impl<'a, L: OwnedLockable<'a>> LockCollection<L> {
- /// Creates a new collection of owned locks.
- ///
- /// Because the locks are owned, there's no need to do any checks for
- /// duplicate values.
- #[must_use]
- pub const fn new(collection: L) -> Self {
- Self { collection }
- }
-
- /// Creates a new collection of owned locks.
- ///
- /// Because the locks are owned, there's no need to do any checks for
- /// duplicate values.
- #[must_use]
- pub const fn new_ref(collection: &L) -> LockCollection<&L> {
- LockCollection { collection }
- }
-}
-
-impl<L> LockCollection<L> {
- /// Creates a new collections of locks.
- ///
- /// # Safety
- ///
- /// This results in undefined behavior if any locks are presented twice
- /// within this collection.
- #[must_use]
- pub const unsafe fn new_unchecked(collection: L) -> Self {
- Self { collection }
- }
-}
-
-impl<'a, L: Lockable<'a>> LockCollection<L> {
- /// Creates a new collection of locks.
- ///
- /// This returns `None` if any locks are found twice in the given
- /// collection.
- ///
- /// # Performance
- ///
- /// This does a check at runtime to make sure that the collection contains
- /// no two copies of the same lock. This is an `O(n^2)` operation. Prefer
- /// [`LockCollection::new`] or [`LockCollection::new_ref`] instead.
- #[must_use]
- pub fn try_new(collection: L) -> Option<Self> {
- let ptrs = collection.get_ptrs();
- if contains_duplicates(&ptrs) {
- return None;
- }
-
- Some(Self { collection })
- }
-
- /// Locks the lockable type and returns a guard that can be used to access
- /// the underlying data.
- pub fn lock<'key: 'a, Key: Keyable + 'key>(&'a self, key: Key) -> LockGuard<'a, 'key, L, Key> {
- LockGuard {
- // safety: we have the thread's key
- guard: unsafe { self.collection.lock() },
- key,
- _phantom: PhantomData,
- }
- }
-
- /// Attempts to lock the guard without blocking.
- ///
- /// If successful, this method returns a guard that can be used to access
- /// the data. Otherwise, `None` is returned.
- pub fn try_lock<'key: 'a, Key: Keyable + 'key>(
- &'a self,
- key: Key,
- ) -> Option<LockGuard<'a, 'key, L, Key>> {
- // safety: we have the thread's key
- unsafe { self.collection.try_lock() }.map(|guard| LockGuard {
- guard,
- key,
- _phantom: PhantomData,
- })
- }
-
- /// Unlocks the underlying lockable data type, returning the key that's
- /// associated with it.
- #[allow(clippy::missing_const_for_fn)]
- pub fn unlock<'key: 'a, Key: Keyable + 'key>(guard: LockGuard<'a, 'key, L, Key>) -> Key {
- drop(guard.guard);
- guard.key
- }
-}
-
-impl<'a, L: 'a> LockCollection<L>
-where
- &'a L: IntoIterator,
-{
- /// Returns an iterator over references to each value in the collection.
- pub fn iter(&'a self) -> <&'a L as IntoIterator>::IntoIter {
- self.into_iter()
- }
-}
-
-impl<'a, L: 'a> LockCollection<L>
-where
- &'a mut L: IntoIterator,
-{
- /// Returns an iterator over mutable references to each value in the
- /// collection.
- pub fn iter_mut(&'a mut self) -> <&'a mut L as IntoIterator>::IntoIter {
- self.into_iter()
- }
-}
-
-impl<'a, 'key: 'a, L: Lockable<'a>, Key: Keyable> Deref for LockGuard<'a, 'key, L, Key> {
- type Target = L::Output;
-
- fn deref(&self) -> &Self::Target {
- &self.guard
- }
-}
-
-impl<'a, 'key: 'a, L: Lockable<'a>, Key: Keyable> DerefMut for LockGuard<'a, 'key, L, Key> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.guard
- }
-}
diff --git a/src/collection/collection.rs b/src/collection/collection.rs
new file mode 100644
index 0000000..eb3bb69
--- /dev/null
+++ b/src/collection/collection.rs
@@ -0,0 +1,208 @@
+use std::marker::PhantomData;
+
+use crate::{key::Keyable, Lockable, OwnedLockable};
+
+use super::{LockCollection, LockGuard};
+
+/// returns `true` if the list contains a duplicate
+#[must_use]
+fn contains_duplicates(l: &[usize]) -> bool {
+ for i in 0..l.len() {
+ for j in (i + 1)..l.len() {
+ if l[i] == l[j] {
+ return true;
+ }
+ }
+ }
+
+ false
+}
+
+impl<'a, L: OwnedLockable<'a>> From<L> for LockCollection<L> {
+ fn from(value: L) -> Self {
+ Self::new(value)
+ }
+}
+
+impl<'a, L: OwnedLockable<'a>> AsRef<L> for LockCollection<L> {
+ fn as_ref(&self) -> &L {
+ &self.collection
+ }
+}
+
+impl<'a, L: OwnedLockable<'a>> AsMut<L> for LockCollection<L> {
+ fn as_mut(&mut self) -> &mut L {
+ &mut self.collection
+ }
+}
+
+impl<'a, L: OwnedLockable<'a>> AsRef<Self> for LockCollection<L> {
+ fn as_ref(&self) -> &Self {
+ self
+ }
+}
+
+impl<'a, L: OwnedLockable<'a>> AsMut<Self> for LockCollection<L> {
+ fn as_mut(&mut self) -> &mut Self {
+ self
+ }
+}
+
+impl<L: IntoIterator> IntoIterator for LockCollection<L> {
+ type Item = L::Item;
+ type IntoIter = L::IntoIter;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.collection.into_iter()
+ }
+}
+
+impl<'a, L> IntoIterator for &'a LockCollection<L>
+where
+ &'a L: IntoIterator,
+{
+ type Item = <&'a L as IntoIterator>::Item;
+ type IntoIter = <&'a L as IntoIterator>::IntoIter;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.collection.into_iter()
+ }
+}
+
+impl<'a, L> IntoIterator for &'a mut LockCollection<L>
+where
+ &'a mut L: IntoIterator,
+{
+ type Item = <&'a mut L as IntoIterator>::Item;
+ type IntoIter = <&'a mut L as IntoIterator>::IntoIter;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.collection.into_iter()
+ }
+}
+
+impl<'a, L: OwnedLockable<'a>, I: FromIterator<L> + OwnedLockable<'a>> FromIterator<L>
+ for LockCollection<I>
+{
+ fn from_iter<T: IntoIterator<Item = L>>(iter: T) -> Self {
+ let iter: I = iter.into_iter().collect();
+ Self::new(iter)
+ }
+}
+
+impl<'a, E: OwnedLockable<'a> + Extend<L>, L: OwnedLockable<'a>> Extend<L> for LockCollection<E> {
+ fn extend<T: IntoIterator<Item = L>>(&mut self, iter: T) {
+ self.collection.extend(iter)
+ }
+}
+
+impl<'a, L: OwnedLockable<'a>> LockCollection<L> {
+ /// Creates a new collection of owned locks.
+ ///
+ /// Because the locks are owned, there's no need to do any checks for
+ /// duplicate values.
+ #[must_use]
+ pub const fn new(collection: L) -> Self {
+ Self { collection }
+ }
+
+ /// Creates a new collection of owned locks.
+ ///
+ /// Because the locks are owned, there's no need to do any checks for
+ /// duplicate values.
+ #[must_use]
+ pub const fn new_ref(collection: &L) -> LockCollection<&L> {
+ LockCollection { collection }
+ }
+}
+
+impl<L> LockCollection<L> {
+ /// Creates a new collections of locks.
+ ///
+ /// # Safety
+ ///
+ /// This results in undefined behavior if any locks are presented twice
+ /// within this collection.
+ #[must_use]
+ pub const unsafe fn new_unchecked(collection: L) -> Self {
+ Self { collection }
+ }
+}
+
+impl<'a, L: Lockable<'a>> LockCollection<L> {
+ /// Creates a new collection of locks.
+ ///
+ /// This returns `None` if any locks are found twice in the given
+ /// collection.
+ ///
+ /// # Performance
+ ///
+ /// This does a check at runtime to make sure that the collection contains
+ /// no two copies of the same lock. This is an `O(n^2)` operation. Prefer
+ /// [`LockCollection::new`] or [`LockCollection::new_ref`] instead.
+ #[must_use]
+ pub fn try_new(collection: L) -> Option<Self> {
+ let ptrs = collection.get_ptrs();
+ if contains_duplicates(&ptrs) {
+ return None;
+ }
+
+ Some(Self { collection })
+ }
+
+ /// Locks the lockable type and returns a guard that can be used to access
+ /// the underlying data.
+ pub fn lock<'key: 'a, Key: Keyable + 'key>(&'a self, key: Key) -> LockGuard<'a, 'key, L, Key> {
+ LockGuard {
+ // safety: we have the thread's key
+ guard: unsafe { self.collection.lock() },
+ key,
+ _phantom: PhantomData,
+ }
+ }
+
+ /// Attempts to lock the guard without blocking.
+ ///
+ /// If successful, this method returns a guard that can be used to access
+ /// the data. Otherwise, `None` is returned.
+ pub fn try_lock<'key: 'a, Key: Keyable + 'key>(
+ &'a self,
+ key: Key,
+ ) -> Option<LockGuard<'a, 'key, L, Key>> {
+ // safety: we have the thread's key
+ unsafe { self.collection.try_lock() }.map(|guard| LockGuard {
+ guard,
+ key,
+ _phantom: PhantomData,
+ })
+ }
+
+ /// Unlocks the underlying lockable data type, returning the key that's
+ /// associated with it.
+ #[allow(clippy::missing_const_for_fn)]
+ pub fn unlock<'key: 'a, Key: Keyable + 'key>(guard: LockGuard<'a, 'key, L, Key>) -> Key {
+ drop(guard.guard);
+ guard.key
+ }
+}
+
+impl<'a, L: 'a> LockCollection<L>
+where
+ &'a L: IntoIterator,
+{
+ /// Returns an iterator over references to each value in the collection.
+ pub fn iter(&'a self) -> <&'a L as IntoIterator>::IntoIter {
+ self.into_iter()
+ }
+}
+
+impl<'a, L: 'a> LockCollection<L>
+where
+ &'a mut L: IntoIterator,
+{
+ /// Returns an iterator over mutable references to each value in the
+ /// collection.
+ pub fn iter_mut(&'a mut self) -> <&'a mut L as IntoIterator>::IntoIter {
+ self.into_iter()
+ }
+}
diff --git a/src/collection/guard.rs b/src/collection/guard.rs
new file mode 100644
index 0000000..110a935
--- /dev/null
+++ b/src/collection/guard.rs
@@ -0,0 +1,19 @@
+use std::ops::{Deref, DerefMut};
+
+use crate::{key::Keyable, Lockable};
+
+use super::LockGuard;
+
+impl<'a, 'key: 'a, L: Lockable<'a>, Key: Keyable> Deref for LockGuard<'a, 'key, L, Key> {
+ type Target = L::Output;
+
+ fn deref(&self) -> &Self::Target {
+ &self.guard
+ }
+}
+
+impl<'a, 'key: 'a, L: Lockable<'a>, Key: Keyable> DerefMut for LockGuard<'a, 'key, L, Key> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.guard
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index f51adb2..dbe095c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -3,6 +3,7 @@
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::declare_interior_mutable_const)]
#![allow(clippy::semicolon_if_nothing_returned)]
+#![allow(clippy::module_inception)]
mod collection;
mod lockable;
@@ -12,7 +13,7 @@ pub mod mutex;
pub mod rwlock;
pub use collection::LockCollection;
-pub use lockable::Lockable;
+pub use lockable::{Lockable, OwnedLockable};
#[cfg(feature = "spin")]
pub use mutex::SpinLock;
diff --git a/src/mutex.rs b/src/mutex.rs
index 0d67f33..db0147f 100644
--- a/src/mutex.rs
+++ b/src/mutex.rs
@@ -1,12 +1,14 @@
use std::cell::UnsafeCell;
-use std::fmt::Debug;
use std::marker::PhantomData;
-use std::ops::{Deref, DerefMut};
use lock_api::RawMutex;
use crate::key::Keyable;
+mod guard;
+mod mutex;
+mod mutex_ref;
+
/// A spinning mutex
#[cfg(feature = "spin")]
pub type SpinLock<T> = Mutex<T, spin::Mutex<()>>;
@@ -38,34 +40,6 @@ pub struct Mutex<T: ?Sized, R> {
/// A reference to a mutex that unlocks it when dropped
pub struct MutexRef<'a, T: ?Sized + 'a, R: RawMutex>(&'a Mutex<T, R>);
-impl<'a, T: ?Sized + 'a, R: RawMutex> Drop for MutexRef<'a, T, R> {
- fn drop(&mut self) {
- // safety: this guard is being destroyed, so the data cannot be
- // accessed without locking again
- unsafe { self.0.force_unlock() }
- }
-}
-
-impl<'a, T: ?Sized + 'a, R: RawMutex> Deref for MutexRef<'a, T, R> {
- type Target = T;
-
- fn deref(&self) -> &Self::Target {
- // safety: this is the only type that can use `value`, and there's
- // a reference to this type, so there cannot be any mutable
- // references to this value.
- unsafe { &*self.0.value.get() }
- }
-}
-
-impl<'a, T: ?Sized + 'a, R: RawMutex> DerefMut for MutexRef<'a, T, R> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- // safety: this is the only type that can use `value`, and we have a
- // mutable reference to this type, so there cannot be any other
- // references to this value.
- unsafe { &mut *self.0.value.get() }
- }
-}
-
/// An RAII implementation of a “scoped lock” of a mutex. When this structure
/// is dropped (falls out of scope), the lock will be unlocked.
///
@@ -78,234 +52,3 @@ pub struct MutexGuard<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable + 'key, R: RawM
thread_key: Key,
_phantom: PhantomData<&'key ()>,
}
-
-impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawMutex> Deref
- for MutexGuard<'a, 'key, T, Key, R>
-{
- type Target = T;
-
- fn deref(&self) -> &Self::Target {
- &self.mutex
- }
-}
-
-impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawMutex> DerefMut
- for MutexGuard<'a, 'key, T, Key, R>
-{
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.mutex
- }
-}
-
-impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawMutex> MutexGuard<'a, 'key, T, Key, R> {
- /// Create a guard to the given mutex. Undefined if multiple guards to the
- /// same mutex exist at once.
- #[must_use]
- const unsafe fn new(mutex: &'a Mutex<T, R>, thread_key: Key) -> Self {
- Self {
- mutex: MutexRef(mutex),
- thread_key,
- _phantom: PhantomData,
- }
- }
-}
-
-impl<T, R: RawMutex> Mutex<T, R> {
- /// Create a new unlocked `Mutex`.
- ///
- /// # Examples
- ///
- /// ```
- /// use happylock::Mutex;
- ///
- /// let mutex = Mutex::new(0);
- /// ```
- #[must_use]
- pub const fn new(value: T) -> Self {
- Self {
- raw: R::INIT,
- value: UnsafeCell::new(value),
- }
- }
-}
-
-impl<T: ?Sized, R> Debug for Mutex<T, R> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.write_str(&format!("Mutex<{}>", std::any::type_name::<T>()))
- }
-}
-
-impl<T, R: RawMutex> From<T> for Mutex<T, R> {
- fn from(value: T) -> Self {
- Self::new(value)
- }
-}
-
-impl<T: ?Sized, R> AsMut<T> for Mutex<T, R> {
- fn as_mut(&mut self) -> &mut T {
- self.get_mut()
- }
-}
-
-impl<T, R> Mutex<T, R> {
- /// Consumes this mutex, returning the underlying data.
- ///
- /// # Examples
- ///
- /// ```
- /// use happylock::Mutex;
- ///
- /// let mutex = Mutex::new(0);
- /// assert_eq!(mutex.into_inner(), 0);
- /// ```
- #[must_use]
- pub fn into_inner(self) -> T {
- self.value.into_inner()
- }
-}
-
-impl<T: ?Sized, R> Mutex<T, R> {
- /// Returns a mutable reference to the underlying data.
- ///
- /// Since this call borrows `Mutex` mutably, no actual locking is taking
- /// place. The mutable borrow statically guarantees that no locks exist.
- ///
- /// # Examples
- ///
- /// ```
- /// use happylock::{ThreadKey, Mutex};
- ///
- /// let key = ThreadKey::lock().unwrap();
- /// let mut mutex = Mutex::new(0);
- /// *mutex.get_mut() = 10;
- /// assert_eq!(*mutex.lock(key), 10);
- /// ```
- #[must_use]
- pub fn get_mut(&mut self) -> &mut T {
- self.value.get_mut()
- }
-}
-
-impl<T: ?Sized, R: RawMutex> Mutex<T, R> {
- /// Block the thread until this mutex can be locked, and lock it.
- ///
- /// Upon returning, the thread is the only thread with a lock on the
- /// `Mutex`. A [`MutexGuard`] is returned to allow a scoped unlock of this
- /// `Mutex`. When the guard is dropped, this `Mutex` will unlock.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::{thread, sync::Arc};
- /// use happylock::{Mutex, ThreadKey};
- ///
- /// let mutex = Arc::new(Mutex::new(0));
- /// let c_mutex = Arc::clone(&mutex);
- ///
- /// thread::spawn(move || {
- /// let key = ThreadKey::lock().unwrap();
- /// *c_mutex.lock(key) = 10;
- /// }).join().expect("thread::spawn failed");
- ///
- /// let key = ThreadKey::lock().unwrap();
- /// assert_eq!(*mutex.lock(key), 10);
- /// ```
- pub fn lock<'s, 'k: 's, Key: Keyable>(&'s self, key: Key) -> MutexGuard<'_, 'k, T, Key, R> {
- unsafe {
- self.raw.lock();
-
- // safety: we just locked the mutex
- MutexGuard::new(self, key)
- }
- }
-
- /// Lock without a [`ThreadKey`]. You must exclusively own the
- /// [`ThreadKey`] as long as the [`MutexRef`] is alive. This may cause
- /// deadlock if called multiple times without unlocking first.
- pub(crate) unsafe fn lock_no_key(&self) -> MutexRef<'_, T, R> {
- self.raw.lock();
-
- MutexRef(self)
- }
-
- /// Attempts to lock the `Mutex` without blocking.
- ///
- /// # Errors
- ///
- /// Returns [`Err`] if the `Mutex` cannot be locked without blocking.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::{thread, sync::Arc};
- /// use happylock::{Mutex, ThreadKey};
- ///
- /// let mutex = Arc::new(Mutex::new(0));
- /// let c_mutex = Arc::clone(&mutex);
- ///
- /// thread::spawn(move || {
- /// let key = ThreadKey::lock().unwrap();
- /// let mut lock = c_mutex.try_lock(key);
- /// if let Some(mut lock) = lock {
- /// *lock = 10;
- /// } else {
- /// println!("try_lock failed");
- /// }
- /// }).join().expect("thread::spawn failed");
- ///
- /// let key = ThreadKey::lock().unwrap();
- /// assert_eq!(*mutex.lock(key), 10);
- /// ```
- pub fn try_lock<'s, 'a: 's, 'k: 'a, Key: Keyable>(
- &'s self,
- key: Key,
- ) -> Option<MutexGuard<'_, 'k, T, Key, R>> {
- if self.raw.try_lock() {
- // safety: we just locked the mutex
- Some(unsafe { MutexGuard::new(self, key) })
- } else {
- None
- }
- }
-
- /// Lock without a [`ThreadKey`]. It is undefined behavior to do this without
- /// owning the [`ThreadKey`].
- pub(crate) unsafe fn try_lock_no_key(&self) -> Option<MutexRef<'_, T, R>> {
- self.raw.try_lock().then_some(MutexRef(self))
- }
-
- /// Forcibly unlocks the `Lock`.
- ///
- /// # Safety
- ///
- /// This should only be called if there are no references to any
- /// [`MutexGuard`]s for this mutex in the program.
- unsafe fn force_unlock(&self) {
- self.raw.unlock();
- }
-
- /// Consumes the [`MutexGuard`], and consequently unlocks its `Mutex`.
- ///
- /// # Examples
- ///
- /// ```
- /// use happylock::{ThreadKey, Mutex};
- ///
- /// let key = ThreadKey::lock().unwrap();
- /// let mutex = Mutex::new(0);
- ///
- /// let mut guard = mutex.lock(key);
- /// *guard += 20;
- ///
- /// let key = Mutex::unlock(guard);
- /// ```
- pub fn unlock<'a, 'k: 'a, Key: Keyable + 'k>(guard: MutexGuard<'a, 'k, T, Key, R>) -> Key {
- unsafe {
- guard.mutex.0.force_unlock();
- }
- guard.thread_key
- }
-}
-
-unsafe impl<R: RawMutex + Send, T: ?Sized + Send> Send for Mutex<T, R> {}
-unsafe impl<R: RawMutex + Sync, T: ?Sized + Send + Sync> Sync for Mutex<T, R> {}
diff --git a/src/mutex/guard.rs b/src/mutex/guard.rs
new file mode 100644
index 0000000..b4005e1
--- /dev/null
+++ b/src/mutex/guard.rs
@@ -0,0 +1,39 @@
+use std::marker::PhantomData;
+use std::ops::{Deref, DerefMut};
+
+use lock_api::RawMutex;
+
+use crate::key::Keyable;
+
+use super::{Mutex, MutexGuard, MutexRef};
+
+impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawMutex> Deref
+ for MutexGuard<'a, 'key, T, Key, R>
+{
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ &self.mutex
+ }
+}
+
+impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawMutex> DerefMut
+ for MutexGuard<'a, 'key, T, Key, R>
+{
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.mutex
+ }
+}
+
+impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawMutex> MutexGuard<'a, 'key, T, Key, R> {
+ /// Create a guard to the given mutex. Undefined if multiple guards to the
+ /// same mutex exist at once.
+ #[must_use]
+ pub(super) const unsafe fn new(mutex: &'a Mutex<T, R>, thread_key: Key) -> Self {
+ Self {
+ mutex: MutexRef(mutex),
+ thread_key,
+ _phantom: PhantomData,
+ }
+ }
+}
diff --git a/src/mutex/mutex.rs b/src/mutex/mutex.rs
new file mode 100644
index 0000000..ce93cae
--- /dev/null
+++ b/src/mutex/mutex.rs
@@ -0,0 +1,208 @@
+use std::cell::UnsafeCell;
+use std::fmt::Debug;
+
+use lock_api::RawMutex;
+
+use crate::key::Keyable;
+
+use super::{Mutex, MutexGuard, MutexRef};
+
+impl<T, R: RawMutex> Mutex<T, R> {
+ /// Create a new unlocked `Mutex`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use happylock::Mutex;
+ ///
+ /// let mutex = Mutex::new(0);
+ /// ```
+ #[must_use]
+ pub const fn new(value: T) -> Self {
+ Self {
+ raw: R::INIT,
+ value: UnsafeCell::new(value),
+ }
+ }
+}
+
+impl<T: ?Sized, R> Debug for Mutex<T, R> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_str(&format!("Mutex<{}>", std::any::type_name::<T>()))
+ }
+}
+
+impl<T, R: RawMutex> From<T> for Mutex<T, R> {
+ fn from(value: T) -> Self {
+ Self::new(value)
+ }
+}
+
+impl<T: ?Sized, R> AsMut<T> for Mutex<T, R> {
+ fn as_mut(&mut self) -> &mut T {
+ self.get_mut()
+ }
+}
+
+impl<T, R> Mutex<T, R> {
+ /// Consumes this mutex, returning the underlying data.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use happylock::Mutex;
+ ///
+ /// let mutex = Mutex::new(0);
+ /// assert_eq!(mutex.into_inner(), 0);
+ /// ```
+ #[must_use]
+ pub fn into_inner(self) -> T {
+ self.value.into_inner()
+ }
+}
+
+impl<T: ?Sized, R> Mutex<T, R> {
+ /// Returns a mutable reference to the underlying data.
+ ///
+ /// Since this call borrows `Mutex` mutably, no actual locking is taking
+ /// place. The mutable borrow statically guarantees that no locks exist.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use happylock::{ThreadKey, Mutex};
+ ///
+ /// let key = ThreadKey::lock().unwrap();
+ /// let mut mutex = Mutex::new(0);
+ /// *mutex.get_mut() = 10;
+ /// assert_eq!(*mutex.lock(key), 10);
+ /// ```
+ #[must_use]
+ pub fn get_mut(&mut self) -> &mut T {
+ self.value.get_mut()
+ }
+}
+
+impl<T: ?Sized, R: RawMutex> Mutex<T, R> {
+ /// Block the thread until this mutex can be locked, and lock it.
+ ///
+ /// Upon returning, the thread is the only thread with a lock on the
+ /// `Mutex`. A [`MutexGuard`] is returned to allow a scoped unlock of this
+ /// `Mutex`. When the guard is dropped, this `Mutex` will unlock.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::{thread, sync::Arc};
+ /// use happylock::{Mutex, ThreadKey};
+ ///
+ /// let mutex = Arc::new(Mutex::new(0));
+ /// let c_mutex = Arc::clone(&mutex);
+ ///
+ /// thread::spawn(move || {
+ /// let key = ThreadKey::lock().unwrap();
+ /// *c_mutex.lock(key) = 10;
+ /// }).join().expect("thread::spawn failed");
+ ///
+ /// let key = ThreadKey::lock().unwrap();
+ /// assert_eq!(*mutex.lock(key), 10);
+ /// ```
+ pub fn lock<'s, 'k: 's, Key: Keyable>(&'s self, key: Key) -> MutexGuard<'_, 'k, T, Key, R> {
+ unsafe {
+ self.raw.lock();
+
+ // safety: we just locked the mutex
+ MutexGuard::new(self, key)
+ }
+ }
+
+ /// Lock without a [`ThreadKey`]. You must exclusively own the
+ /// [`ThreadKey`] as long as the [`MutexRef`] is alive. This may cause
+ /// deadlock if called multiple times without unlocking first.
+ pub(crate) unsafe fn lock_no_key(&self) -> MutexRef<'_, T, R> {
+ self.raw.lock();
+
+ MutexRef(self)
+ }
+
+ /// Attempts to lock the `Mutex` without blocking.
+ ///
+ /// # Errors
+ ///
+ /// Returns [`Err`] if the `Mutex` cannot be locked without blocking.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::{thread, sync::Arc};
+ /// use happylock::{Mutex, ThreadKey};
+ ///
+ /// let mutex = Arc::new(Mutex::new(0));
+ /// let c_mutex = Arc::clone(&mutex);
+ ///
+ /// thread::spawn(move || {
+ /// let key = ThreadKey::lock().unwrap();
+ /// let mut lock = c_mutex.try_lock(key);
+ /// if let Some(mut lock) = lock {
+ /// *lock = 10;
+ /// } else {
+ /// println!("try_lock failed");
+ /// }
+ /// }).join().expect("thread::spawn failed");
+ ///
+ /// let key = ThreadKey::lock().unwrap();
+ /// assert_eq!(*mutex.lock(key), 10);
+ /// ```
+ pub fn try_lock<'s, 'a: 's, 'k: 'a, Key: Keyable>(
+ &'s self,
+ key: Key,
+ ) -> Option<MutexGuard<'_, 'k, T, Key, R>> {
+ if self.raw.try_lock() {
+ // safety: we just locked the mutex
+ Some(unsafe { MutexGuard::new(self, key) })
+ } else {
+ None
+ }
+ }
+
+ /// Lock without a [`ThreadKey`]. It is undefined behavior to do this without
+ /// owning the [`ThreadKey`].
+ pub(crate) unsafe fn try_lock_no_key(&self) -> Option<MutexRef<'_, T, R>> {
+ self.raw.try_lock().then_some(MutexRef(self))
+ }
+
+ /// Forcibly unlocks the `Lock`.
+ ///
+ /// # Safety
+ ///
+ /// This should only be called if there are no references to any
+ /// [`MutexGuard`]s for this mutex in the program.
+ pub(super) unsafe fn force_unlock(&self) {
+ self.raw.unlock();
+ }
+
+ /// Consumes the [`MutexGuard`], and consequently unlocks its `Mutex`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use happylock::{ThreadKey, Mutex};
+ ///
+ /// let key = ThreadKey::lock().unwrap();
+ /// let mutex = Mutex::new(0);
+ ///
+ /// let mut guard = mutex.lock(key);
+ /// *guard += 20;
+ ///
+ /// let key = Mutex::unlock(guard);
+ /// ```
+ pub fn unlock<'a, 'k: 'a, Key: Keyable + 'k>(guard: MutexGuard<'a, 'k, T, Key, R>) -> Key {
+ unsafe {
+ guard.mutex.0.force_unlock();
+ }
+ guard.thread_key
+ }
+}
+
+unsafe impl<R: RawMutex + Send, T: ?Sized + Send> Send for Mutex<T, R> {}
+unsafe impl<R: RawMutex + Sync, T: ?Sized + Send + Sync> Sync for Mutex<T, R> {}
diff --git a/src/mutex/mutex_ref.rs b/src/mutex/mutex_ref.rs
new file mode 100644
index 0000000..5222719
--- /dev/null
+++ b/src/mutex/mutex_ref.rs
@@ -0,0 +1,33 @@
+use std::ops::{Deref, DerefMut};
+
+use lock_api::RawMutex;
+
+use super::MutexRef;
+
+impl<'a, T: ?Sized + 'a, R: RawMutex> Drop for MutexRef<'a, T, R> {
+ fn drop(&mut self) {
+ // safety: this guard is being destroyed, so the data cannot be
+ // accessed without locking again
+ unsafe { self.0.force_unlock() }
+ }
+}
+
+impl<'a, T: ?Sized + 'a, R: RawMutex> Deref for MutexRef<'a, T, R> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ // safety: this is the only type that can use `value`, and there's
+ // a reference to this type, so there cannot be any mutable
+ // references to this value.
+ unsafe { &*self.0.value.get() }
+ }
+}
+
+impl<'a, T: ?Sized + 'a, R: RawMutex> DerefMut for MutexRef<'a, T, R> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ // safety: this is the only type that can use `value`, and we have a
+ // mutable reference to this type, so there cannot be any other
+ // references to this value.
+ unsafe { &mut *self.0.value.get() }
+ }
+}
diff --git a/src/rwlock.rs b/src/rwlock.rs
index 259c247..06862cd 100644
--- a/src/rwlock.rs
+++ b/src/rwlock.rs
@@ -1,12 +1,18 @@
use std::cell::UnsafeCell;
-use std::fmt::Debug;
use std::marker::PhantomData;
-use std::ops::{Deref, DerefMut};
use lock_api::RawRwLock;
use crate::key::Keyable;
+mod rwlock;
+
+mod read_lock;
+mod write_lock;
+
+mod read_guard;
+mod write_guard;
+
#[cfg(feature = "spin")]
pub type SpinRwLock<T> = RwLock<T, spin::RwLock<()>>;
@@ -37,369 +43,3 @@ pub struct RwLockWriteGuard<'a, 'key, T: ?Sized, Key: Keyable + 'key, R: RawRwLo
thread_key: Key,
_phantom: PhantomData<&'key ()>,
}
-
-unsafe impl<R: RawRwLock + Send, T: ?Sized + Send> Send for RwLock<T, R> {}
-unsafe impl<R: RawRwLock + Sync, T: ?Sized + Send + Sync> Sync for RwLock<T, R> {}
-
-impl<'a, T: ?Sized + 'a, R: RawRwLock> Deref for RwLockReadRef<'a, T, R> {
- type Target = T;
-
- fn deref(&self) -> &Self::Target {
- // safety: this is the only type that can use `value`, and there's
- // a reference to this type, so there cannot be any mutable
- // references to this value.
- unsafe { &*self.0.value.get() }
- }
-}
-
-impl<'a, T: ?Sized + 'a, R: RawRwLock> Drop for RwLockReadRef<'a, T, R> {
- fn drop(&mut self) {
- // safety: this guard is being destroyed, so the data cannot be
- // accessed without locking again
- unsafe { self.0.force_unlock_read() }
- }
-}
-
-impl<'a, T: ?Sized + 'a, R: RawRwLock> Deref for RwLockWriteRef<'a, T, R> {
- type Target = T;
-
- fn deref(&self) -> &Self::Target {
- // safety: this is the only type that can use `value`, and there's
- // a reference to this type, so there cannot be any mutable
- // references to this value.
- unsafe { &*self.0.value.get() }
- }
-}
-
-impl<'a, T: ?Sized + 'a, R: RawRwLock> DerefMut for RwLockWriteRef<'a, T, R> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- // safety: this is the only type that can use `value`, and we have a
- // mutable reference to this type, so there cannot be any other
- // references to this value.
- unsafe { &mut *self.0.value.get() }
- }
-}
-
-impl<'a, T: ?Sized + 'a, R: RawRwLock> Drop for RwLockWriteRef<'a, T, R> {
- fn drop(&mut self) {
- // safety: this guard is being destroyed, so the data cannot be
- // accessed without locking again
- unsafe { self.0.force_unlock_write() }
- }
-}
-
-impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock> Deref
- for RwLockReadGuard<'a, 'key, T, Key, R>
-{
- type Target = T;
-
- fn deref(&self) -> &Self::Target {
- &self.rwlock
- }
-}
-
-impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock> Deref
- for RwLockWriteGuard<'a, 'key, T, Key, R>
-{
- type Target = T;
-
- fn deref(&self) -> &Self::Target {
- &self.rwlock
- }
-}
-
-impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock> DerefMut
- for RwLockWriteGuard<'a, 'key, T, Key, R>
-{
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.rwlock
- }
-}
-
-impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock>
- RwLockReadGuard<'a, 'key, T, Key, R>
-{
- /// Create a guard to the given mutex. Undefined if multiple guards to the
- /// same mutex exist at once.
- #[must_use]
- const unsafe fn new(rwlock: &'a RwLock<T, R>, thread_key: Key) -> Self {
- Self {
- rwlock: RwLockReadRef(rwlock),
- thread_key,
- _phantom: PhantomData,
- }
- }
-}
-
-impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock>
- RwLockWriteGuard<'a, 'key, T, Key, R>
-{
- /// Create a guard to the given mutex. Undefined if multiple guards to the
- /// same mutex exist at once.
- #[must_use]
- const unsafe fn new(rwlock: &'a RwLock<T, R>, thread_key: Key) -> Self {
- Self {
- rwlock: RwLockWriteRef(rwlock),
- thread_key,
- _phantom: PhantomData,
- }
- }
-}
-
-impl<T, R: RawRwLock> RwLock<T, R> {
- #[must_use]
- pub const fn new(value: T) -> Self {
- Self {
- value: UnsafeCell::new(value),
- raw: R::INIT,
- }
- }
-}
-
-impl<T: ?Sized, R> Debug for RwLock<T, R> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.write_str(&format!("RwLock<{}>", std::any::type_name::<T>()))
- }
-}
-
-impl<T, R: RawRwLock> From<T> for RwLock<T, R> {
- fn from(value: T) -> Self {
- Self::new(value)
- }
-}
-
-impl<T: ?Sized, R> AsMut<T> for RwLock<T, R> {
- fn as_mut(&mut self) -> &mut T {
- self.get_mut()
- }
-}
-
-impl<'a, T: ?Sized, R> Debug for ReadLock<'a, T, R> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.write_str(&format!("ReadLock<{}>", std::any::type_name::<T>()))
- }
-}
-
-impl<'a, T: ?Sized, R> From<&'a RwLock<T, R>> for ReadLock<'a, T, R> {
- fn from(value: &'a RwLock<T, R>) -> Self {
- Self::new(value)
- }
-}
-
-impl<'a, T: ?Sized, R> AsRef<RwLock<T, R>> for ReadLock<'a, T, R> {
- fn as_ref(&self) -> &RwLock<T, R> {
- self.0
- }
-}
-
-impl<'a, T: ?Sized, R> Debug for WriteLock<'a, T, R> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.write_str(&format!("WriteLock<{}>", std::any::type_name::<T>()))
- }
-}
-
-impl<'a, T: ?Sized, R> From<&'a RwLock<T, R>> for WriteLock<'a, T, R> {
- fn from(value: &'a RwLock<T, R>) -> Self {
- Self::new(value)
- }
-}
-
-impl<'a, T: ?Sized, R> AsRef<RwLock<T, R>> for WriteLock<'a, T, R> {
- fn as_ref(&self) -> &RwLock<T, R> {
- self.0
- }
-}
-
-impl<T, R> RwLock<T, R> {
- pub fn into_inner(self) -> T {
- self.value.into_inner()
- }
-}
-
-impl<T: ?Sized, R> RwLock<T, R> {
- pub fn get_mut(&mut self) -> &mut T {
- self.value.get_mut()
- }
-}
-
-impl<T: ?Sized, R: RawRwLock> RwLock<T, R> {
- pub fn read<'s, 'key: 's, Key: Keyable>(
- &'s self,
- key: Key,
- ) -> RwLockReadGuard<'_, 'key, T, Key, R> {
- unsafe {
- self.raw.lock_shared();
-
- // safety: the lock is locked first
- RwLockReadGuard::new(self, key)
- }
- }
-
- pub(crate) unsafe fn read_no_key(&self) -> RwLockReadRef<'_, T, R> {
- self.raw.lock_shared();
-
- // safety: the lock is locked first
- RwLockReadRef(self)
- }
-
- pub fn try_read<'s, 'key: 's, Key: Keyable>(
- &'s self,
- key: Key,
- ) -> Option<RwLockReadGuard<'_, 'key, T, Key, R>> {
- unsafe {
- if self.raw.try_lock_shared() {
- // safety: the lock is locked first
- Some(RwLockReadGuard::new(self, key))
- } else {
- None
- }
- }
- }
-
- pub(crate) unsafe fn try_read_no_key(&self) -> Option<RwLockReadRef<'_, T, R>> {
- if self.raw.try_lock_shared() {
- // safety: the lock is locked first
- Some(RwLockReadRef(self))
- } else {
- None
- }
- }
-
- pub fn write<'s, 'key: 's, Key: Keyable>(
- &'s self,
- key: Key,
- ) -> RwLockWriteGuard<'_, 'key, T, Key, R> {
- unsafe {
- self.raw.lock_exclusive();
-
- // safety: the lock is locked first
- RwLockWriteGuard::new(self, key)
- }
- }
-
- pub(crate) unsafe fn write_no_key(&self) -> RwLockWriteRef<'_, T, R> {
- self.raw.lock_exclusive();
-
- // safety: the lock is locked first
- RwLockWriteRef(self)
- }
-
- pub fn try_write<'s, 'key: 's, Key: Keyable>(
- &'s self,
- key: Key,
- ) -> Option<RwLockWriteGuard<'_, 'key, T, Key, R>> {
- unsafe {
- if self.raw.try_lock_exclusive() {
- // safety: the lock is locked first
- Some(RwLockWriteGuard::new(self, key))
- } else {
- None
- }
- }
- }
-
- pub(crate) unsafe fn try_write_no_key(&self) -> Option<RwLockWriteRef<'_, T, R>> {
- if self.raw.try_lock_exclusive() {
- // safety: the lock is locked first
- Some(RwLockWriteRef(self))
- } else {
- None
- }
- }
-
- unsafe fn force_unlock_read(&self) {
- self.raw.unlock_shared();
- }
-
- unsafe fn force_unlock_write(&self) {
- self.raw.unlock_exclusive();
- }
-
- pub fn unlock_read<'key, Key: Keyable + 'key>(
- guard: RwLockReadGuard<'_, 'key, T, Key, R>,
- ) -> Key {
- unsafe {
- guard.rwlock.0.force_unlock_read();
- }
- guard.thread_key
- }
-
- pub fn unlock_write<'key, Key: Keyable + 'key>(
- guard: RwLockWriteGuard<'_, 'key, T, Key, R>,
- ) -> Key {
- unsafe {
- guard.rwlock.0.force_unlock_write();
- }
- guard.thread_key
- }
-}
-
-impl<'a, T: ?Sized, R> ReadLock<'a, T, R> {
- #[must_use]
- pub const fn new(rwlock: &'a RwLock<T, R>) -> Self {
- Self(rwlock)
- }
-}
-
-impl<'a, T: ?Sized, R: RawRwLock> ReadLock<'a, T, R> {
- pub fn lock<'s, 'key: 's, Key: Keyable + 'key>(
- &'s self,
- key: Key,
- ) -> RwLockReadGuard<'_, 'key, T, Key, R> {
- self.0.read(key)
- }
-
- pub(crate) unsafe fn lock_no_key(&self) -> RwLockReadRef<'_, T, R> {
- self.0.read_no_key()
- }
-
- pub fn try_lock<'s, 'key: 's, Key: Keyable + 'key>(
- &'s self,
- key: Key,
- ) -> Option<RwLockReadGuard<'_, 'key, T, Key, R>> {
- self.0.try_read(key)
- }
-
- pub(crate) unsafe fn try_lock_no_key(&self) -> Option<RwLockReadRef<'_, T, R>> {
- self.0.try_read_no_key()
- }
-
- pub fn unlock<'key, Key: Keyable + 'key>(guard: RwLockReadGuard<'_, 'key, T, Key, R>) -> Key {
- RwLock::unlock_read(guard)
- }
-}
-
-impl<'a, T: ?Sized, R> WriteLock<'a, T, R> {
- #[must_use]
- pub const fn new(rwlock: &'a RwLock<T, R>) -> Self {
- Self(rwlock)
- }
-}
-
-impl<'a, T: ?Sized, R: RawRwLock> WriteLock<'a, T, R> {
- pub fn lock<'s, 'key: 's, Key: Keyable + 'key>(
- &'s self,
- key: Key,
- ) -> RwLockWriteGuard<'_, 'key, T, Key, R> {
- self.0.write(key)
- }
-
- pub(crate) unsafe fn lock_no_key(&self) -> RwLockWriteRef<'_, T, R> {
- self.0.write_no_key()
- }
-
- pub fn try_lock<'s, 'key: 's, Key: Keyable + 'key>(
- &'s self,
- key: Key,
- ) -> Option<RwLockWriteGuard<'_, 'key, T, Key, R>> {
- self.0.try_write(key)
- }
-
- pub(crate) unsafe fn try_lock_no_key(&self) -> Option<RwLockWriteRef<'_, T, R>> {
- self.0.try_write_no_key()
- }
-
- pub fn unlock<'key, Key: Keyable + 'key>(guard: RwLockWriteGuard<'_, 'key, T, Key, R>) -> Key {
- RwLock::unlock_write(guard)
- }
-}
diff --git a/src/rwlock/read_guard.rs b/src/rwlock/read_guard.rs
new file mode 100644
index 0000000..e967420
--- /dev/null
+++ b/src/rwlock/read_guard.rs
@@ -0,0 +1,52 @@
+use std::marker::PhantomData;
+use std::ops::Deref;
+
+use lock_api::RawRwLock;
+
+use crate::key::Keyable;
+
+use super::{RwLock, RwLockReadGuard, RwLockReadRef};
+
+impl<'a, T: ?Sized + 'a, R: RawRwLock> Deref for RwLockReadRef<'a, T, R> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ // safety: this is the only type that can use `value`, and there's
+ // a reference to this type, so there cannot be any mutable
+ // references to this value.
+ unsafe { &*self.0.value.get() }
+ }
+}
+
+impl<'a, T: ?Sized + 'a, R: RawRwLock> Drop for RwLockReadRef<'a, T, R> {
+ fn drop(&mut self) {
+ // safety: this guard is being destroyed, so the data cannot be
+ // accessed without locking again
+ unsafe { self.0.force_unlock_read() }
+ }
+}
+
+impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock> Deref
+ for RwLockReadGuard<'a, 'key, T, Key, R>
+{
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ &self.rwlock
+ }
+}
+
+impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock>
+ RwLockReadGuard<'a, 'key, T, Key, R>
+{
+ /// Create a guard to the given mutex. Undefined if multiple guards to the
+ /// same mutex exist at once.
+ #[must_use]
+ pub(super) const unsafe fn new(rwlock: &'a RwLock<T, R>, thread_key: Key) -> Self {
+ Self {
+ rwlock: RwLockReadRef(rwlock),
+ thread_key,
+ _phantom: PhantomData,
+ }
+ }
+}
diff --git a/src/rwlock/read_lock.rs b/src/rwlock/read_lock.rs
new file mode 100644
index 0000000..dbab8de
--- /dev/null
+++ b/src/rwlock/read_lock.rs
@@ -0,0 +1,60 @@
+use std::fmt::Debug;
+
+use lock_api::RawRwLock;
+
+use crate::key::Keyable;
+
+use super::{ReadLock, RwLock, RwLockReadGuard, RwLockReadRef};
+
+impl<'a, T: ?Sized, R> Debug for ReadLock<'a, T, R> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_str(&format!("ReadLock<{}>", std::any::type_name::<T>()))
+ }
+}
+
+impl<'a, T: ?Sized, R> From<&'a RwLock<T, R>> for ReadLock<'a, T, R> {
+ fn from(value: &'a RwLock<T, R>) -> Self {
+ Self::new(value)
+ }
+}
+
+impl<'a, T: ?Sized, R> AsRef<RwLock<T, R>> for ReadLock<'a, T, R> {
+ fn as_ref(&self) -> &RwLock<T, R> {
+ self.0
+ }
+}
+
+impl<'a, T: ?Sized, R> ReadLock<'a, T, R> {
+ #[must_use]
+ pub const fn new(rwlock: &'a RwLock<T, R>) -> Self {
+ Self(rwlock)
+ }
+}
+
+impl<'a, T: ?Sized, R: RawRwLock> ReadLock<'a, T, R> {
+ pub fn lock<'s, 'key: 's, Key: Keyable + 'key>(
+ &'s self,
+ key: Key,
+ ) -> RwLockReadGuard<'_, 'key, T, Key, R> {
+ self.0.read(key)
+ }
+
+ pub(crate) unsafe fn lock_no_key(&self) -> RwLockReadRef<'_, T, R> {
+ self.0.read_no_key()
+ }
+
+ pub fn try_lock<'s, 'key: 's, Key: Keyable + 'key>(
+ &'s self,
+ key: Key,
+ ) -> Option<RwLockReadGuard<'_, 'key, T, Key, R>> {
+ self.0.try_read(key)
+ }
+
+ pub(crate) unsafe fn try_lock_no_key(&self) -> Option<RwLockReadRef<'_, T, R>> {
+ self.0.try_read_no_key()
+ }
+
+ pub fn unlock<'key, Key: Keyable + 'key>(guard: RwLockReadGuard<'_, 'key, T, Key, R>) -> Key {
+ RwLock::unlock_read(guard)
+ }
+}
diff --git a/src/rwlock/rwlock.rs b/src/rwlock/rwlock.rs
new file mode 100644
index 0000000..946f67e
--- /dev/null
+++ b/src/rwlock/rwlock.rs
@@ -0,0 +1,163 @@
+use std::cell::UnsafeCell;
+use std::fmt::Debug;
+
+use lock_api::RawRwLock;
+
+use crate::key::Keyable;
+
+use super::{RwLock, RwLockReadGuard, RwLockReadRef, RwLockWriteGuard, RwLockWriteRef};
+
+impl<T, R: RawRwLock> RwLock<T, R> {
+ #[must_use]
+ pub const fn new(value: T) -> Self {
+ Self {
+ value: UnsafeCell::new(value),
+ raw: R::INIT,
+ }
+ }
+}
+
+impl<T: ?Sized, R> Debug for RwLock<T, R> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_str(&format!("RwLock<{}>", std::any::type_name::<T>()))
+ }
+}
+
+impl<T, R: RawRwLock> From<T> for RwLock<T, R> {
+ fn from(value: T) -> Self {
+ Self::new(value)
+ }
+}
+
+impl<T: ?Sized, R> AsMut<T> for RwLock<T, R> {
+ fn as_mut(&mut self) -> &mut T {
+ self.get_mut()
+ }
+}
+
+impl<T, R> RwLock<T, R> {
+ pub fn into_inner(self) -> T {
+ self.value.into_inner()
+ }
+}
+
+impl<T: ?Sized, R> RwLock<T, R> {
+ pub fn get_mut(&mut self) -> &mut T {
+ self.value.get_mut()
+ }
+}
+
+impl<T: ?Sized, R: RawRwLock> RwLock<T, R> {
+ pub fn read<'s, 'key: 's, Key: Keyable>(
+ &'s self,
+ key: Key,
+ ) -> RwLockReadGuard<'_, 'key, T, Key, R> {
+ unsafe {
+ self.raw.lock_shared();
+
+ // safety: the lock is locked first
+ RwLockReadGuard::new(self, key)
+ }
+ }
+
+ pub(crate) unsafe fn read_no_key(&self) -> RwLockReadRef<'_, T, R> {
+ self.raw.lock_shared();
+
+ // safety: the lock is locked first
+ RwLockReadRef(self)
+ }
+
+ pub fn try_read<'s, 'key: 's, Key: Keyable>(
+ &'s self,
+ key: Key,
+ ) -> Option<RwLockReadGuard<'_, 'key, T, Key, R>> {
+ unsafe {
+ if self.raw.try_lock_shared() {
+ // safety: the lock is locked first
+ Some(RwLockReadGuard::new(self, key))
+ } else {
+ None
+ }
+ }
+ }
+
+ pub(crate) unsafe fn try_read_no_key(&self) -> Option<RwLockReadRef<'_, T, R>> {
+ if self.raw.try_lock_shared() {
+ // safety: the lock is locked first
+ Some(RwLockReadRef(self))
+ } else {
+ None
+ }
+ }
+
+ pub fn write<'s, 'key: 's, Key: Keyable>(
+ &'s self,
+ key: Key,
+ ) -> RwLockWriteGuard<'_, 'key, T, Key, R> {
+ unsafe {
+ self.raw.lock_exclusive();
+
+ // safety: the lock is locked first
+ RwLockWriteGuard::new(self, key)
+ }
+ }
+
+ pub(crate) unsafe fn write_no_key(&self) -> RwLockWriteRef<'_, T, R> {
+ self.raw.lock_exclusive();
+
+ // safety: the lock is locked first
+ RwLockWriteRef(self)
+ }
+
+ pub fn try_write<'s, 'key: 's, Key: Keyable>(
+ &'s self,
+ key: Key,
+ ) -> Option<RwLockWriteGuard<'_, 'key, T, Key, R>> {
+ unsafe {
+ if self.raw.try_lock_exclusive() {
+ // safety: the lock is locked first
+ Some(RwLockWriteGuard::new(self, key))
+ } else {
+ None
+ }
+ }
+ }
+
+ pub(crate) unsafe fn try_write_no_key(&self) -> Option<RwLockWriteRef<'_, T, R>> {
+ if self.raw.try_lock_exclusive() {
+ // safety: the lock is locked first
+ Some(RwLockWriteRef(self))
+ } else {
+ None
+ }
+ }
+
+ pub(super) unsafe fn force_unlock_read(&self) {
+ self.raw.unlock_shared();
+ }
+
+ pub(super) unsafe fn force_unlock_write(&self) {
+ self.raw.unlock_exclusive();
+ }
+
+ pub fn unlock_read<'key, Key: Keyable + 'key>(
+ guard: RwLockReadGuard<'_, 'key, T, Key, R>,
+ ) -> Key {
+ unsafe {
+ guard.rwlock.0.force_unlock_read();
+ }
+ guard.thread_key
+ }
+
+ pub fn unlock_write<'key, Key: Keyable + 'key>(
+ guard: RwLockWriteGuard<'_, 'key, T, Key, R>,
+ ) -> Key {
+ unsafe {
+ guard.rwlock.0.force_unlock_write();
+ }
+ guard.thread_key
+ }
+}
+
+unsafe impl<R: RawRwLock + Send, T: ?Sized + Send> Send for RwLock<T, R> {}
+unsafe impl<R: RawRwLock + Sync, T: ?Sized + Send + Sync> Sync for RwLock<T, R> {}
diff --git a/src/rwlock/write_guard.rs b/src/rwlock/write_guard.rs
new file mode 100644
index 0000000..8f5feb4
--- /dev/null
+++ b/src/rwlock/write_guard.rs
@@ -0,0 +1,69 @@
+use std::marker::PhantomData;
+use std::ops::{Deref, DerefMut};
+
+use lock_api::RawRwLock;
+
+use crate::key::Keyable;
+
+use super::{RwLock, RwLockWriteGuard, RwLockWriteRef};
+
+impl<'a, T: ?Sized + 'a, R: RawRwLock> Deref for RwLockWriteRef<'a, T, R> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ // safety: this is the only type that can use `value`, and there's
+ // a reference to this type, so there cannot be any mutable
+ // references to this value.
+ unsafe { &*self.0.value.get() }
+ }
+}
+
+impl<'a, T: ?Sized + 'a, R: RawRwLock> DerefMut for RwLockWriteRef<'a, T, R> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ // safety: this is the only type that can use `value`, and we have a
+ // mutable reference to this type, so there cannot be any other
+ // references to this value.
+ unsafe { &mut *self.0.value.get() }
+ }
+}
+
+impl<'a, T: ?Sized + 'a, R: RawRwLock> Drop for RwLockWriteRef<'a, T, R> {
+ fn drop(&mut self) {
+ // safety: this guard is being destroyed, so the data cannot be
+ // accessed without locking again
+ unsafe { self.0.force_unlock_write() }
+ }
+}
+
+impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock> Deref
+ for RwLockWriteGuard<'a, 'key, T, Key, R>
+{
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ &self.rwlock
+ }
+}
+
+impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock> DerefMut
+ for RwLockWriteGuard<'a, 'key, T, Key, R>
+{
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.rwlock
+ }
+}
+
+impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock>
+ RwLockWriteGuard<'a, 'key, T, Key, R>
+{
+ /// Create a guard to the given mutex. Undefined if multiple guards to the
+ /// same mutex exist at once.
+ #[must_use]
+ pub(super) const unsafe fn new(rwlock: &'a RwLock<T, R>, thread_key: Key) -> Self {
+ Self {
+ rwlock: RwLockWriteRef(rwlock),
+ thread_key,
+ _phantom: PhantomData,
+ }
+ }
+}
diff --git a/src/rwlock/write_lock.rs b/src/rwlock/write_lock.rs
new file mode 100644
index 0000000..dd204f5
--- /dev/null
+++ b/src/rwlock/write_lock.rs
@@ -0,0 +1,60 @@
+use std::fmt::Debug;
+
+use lock_api::RawRwLock;
+
+use crate::key::Keyable;
+
+use super::{RwLock, RwLockWriteGuard, RwLockWriteRef, WriteLock};
+
+impl<'a, T: ?Sized, R> Debug for WriteLock<'a, T, R> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_str(&format!("WriteLock<{}>", std::any::type_name::<T>()))
+ }
+}
+
+impl<'a, T: ?Sized, R> From<&'a RwLock<T, R>> for WriteLock<'a, T, R> {
+ fn from(value: &'a RwLock<T, R>) -> Self {
+ Self::new(value)
+ }
+}
+
+impl<'a, T: ?Sized, R> AsRef<RwLock<T, R>> for WriteLock<'a, T, R> {
+ fn as_ref(&self) -> &RwLock<T, R> {
+ self.0
+ }
+}
+
+impl<'a, T: ?Sized, R> WriteLock<'a, T, R> {
+ #[must_use]
+ pub const fn new(rwlock: &'a RwLock<T, R>) -> Self {
+ Self(rwlock)
+ }
+}
+
+impl<'a, T: ?Sized, R: RawRwLock> WriteLock<'a, T, R> {
+ pub fn lock<'s, 'key: 's, Key: Keyable + 'key>(
+ &'s self,
+ key: Key,
+ ) -> RwLockWriteGuard<'_, 'key, T, Key, R> {
+ self.0.write(key)
+ }
+
+ pub(crate) unsafe fn lock_no_key(&self) -> RwLockWriteRef<'_, T, R> {
+ self.0.write_no_key()
+ }
+
+ pub fn try_lock<'s, 'key: 's, Key: Keyable + 'key>(
+ &'s self,
+ key: Key,
+ ) -> Option<RwLockWriteGuard<'_, 'key, T, Key, R>> {
+ self.0.try_write(key)
+ }
+
+ pub(crate) unsafe fn try_lock_no_key(&self) -> Option<RwLockWriteRef<'_, T, R>> {
+ self.0.try_write_no_key()
+ }
+
+ pub fn unlock<'key, Key: Keyable + 'key>(guard: RwLockWriteGuard<'_, 'key, T, Key, R>) -> Key {
+ RwLock::unlock_write(guard)
+ }
+}