diff options
| author | Mica White <botahamec@outlook.com> | 2024-03-10 20:21:00 -0400 |
|---|---|---|
| committer | Mica White <botahamec@outlook.com> | 2024-03-10 20:21:00 -0400 |
| commit | fe67aa262f1b04fb6c38683d9221c3a2fafcc35a (patch) | |
| tree | 91366e032219f5e29ff4ba993598ae581aefa829 | |
| parent | e8d25c9e6e7d5c3a5a14219fc77ea98760cef790 (diff) | |
Reorganization
| -rw-r--r-- | src/collection.rs | 224 | ||||
| -rw-r--r-- | src/collection/collection.rs | 208 | ||||
| -rw-r--r-- | src/collection/guard.rs | 19 | ||||
| -rw-r--r-- | src/lib.rs | 3 | ||||
| -rw-r--r-- | src/mutex.rs | 265 | ||||
| -rw-r--r-- | src/mutex/guard.rs | 39 | ||||
| -rw-r--r-- | src/mutex/mutex.rs | 208 | ||||
| -rw-r--r-- | src/mutex/mutex_ref.rs | 33 | ||||
| -rw-r--r-- | src/rwlock.rs | 376 | ||||
| -rw-r--r-- | src/rwlock/read_guard.rs | 52 | ||||
| -rw-r--r-- | src/rwlock/read_lock.rs | 60 | ||||
| -rw-r--r-- | src/rwlock/rwlock.rs | 163 | ||||
| -rw-r--r-- | src/rwlock/write_guard.rs | 69 | ||||
| -rw-r--r-- | src/rwlock/write_lock.rs | 60 |
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 + } +} @@ -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) + } +} |
