summaryrefslogtreecommitdiff
path: root/src/rwlock
diff options
context:
space:
mode:
Diffstat (limited to 'src/rwlock')
-rw-r--r--src/rwlock/read_guard.rs52
-rw-r--r--src/rwlock/read_lock.rs22
-rw-r--r--src/rwlock/rwlock.rs79
-rw-r--r--src/rwlock/write_guard.rs37
-rw-r--r--src/rwlock/write_lock.rs35
5 files changed, 133 insertions, 92 deletions
diff --git a/src/rwlock/read_guard.rs b/src/rwlock/read_guard.rs
index 532a6e7..1eb8bfc 100644
--- a/src/rwlock/read_guard.rs
+++ b/src/rwlock/read_guard.rs
@@ -1,3 +1,4 @@
+use std::fmt::{Debug, Display};
use std::marker::PhantomData;
use std::ops::Deref;
@@ -7,6 +8,18 @@ use crate::key::Keyable;
use super::{RwLock, RwLockReadGuard, RwLockReadRef};
+impl<'a, T: Debug + ?Sized + 'a, R: RawRwLock> Debug for RwLockReadRef<'a, T, R> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ Debug::fmt(&**self, f)
+ }
+}
+
+impl<'a, T: Display + ?Sized + 'a, R: RawRwLock> Display for RwLockReadRef<'a, T, R> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ Display::fmt(&**self, f)
+ }
+}
+
impl<'a, T: ?Sized + 'a, R: RawRwLock> Deref for RwLockReadRef<'a, T, R> {
type Target = T;
@@ -18,6 +31,12 @@ impl<'a, T: ?Sized + 'a, R: RawRwLock> Deref for RwLockReadRef<'a, T, R> {
}
}
+impl<'a, T: ?Sized + 'a, R: RawRwLock> AsRef<T> for RwLockReadRef<'a, T, R> {
+ fn as_ref(&self) -> &T {
+ self
+ }
+}
+
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
@@ -26,6 +45,31 @@ impl<'a, T: ?Sized + 'a, R: RawRwLock> Drop for RwLockReadRef<'a, T, R> {
}
}
+impl<'a, T: ?Sized + 'a, R: RawRwLock> RwLockReadRef<'a, T, R> {
+ /// Creates an immutable reference for the underlying data of an [`RwLock`]
+ /// without locking it or taking ownership of the key.
+ #[must_use]
+ pub(crate) unsafe fn new(mutex: &'a RwLock<T, R>) -> Self {
+ Self(mutex, PhantomData)
+ }
+}
+
+impl<'a, 'key, T: Debug + ?Sized + 'a, Key: Keyable + 'key, R: RawRwLock> Debug
+ for RwLockReadGuard<'a, 'key, T, Key, R>
+{
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ Debug::fmt(&**self, f)
+ }
+}
+
+impl<'a, 'key, T: Display + ?Sized + 'a, Key: Keyable + 'key, R: RawRwLock> Display
+ for RwLockReadGuard<'a, 'key, T, Key, R>
+{
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ Display::fmt(&**self, f)
+ }
+}
+
impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock> Deref
for RwLockReadGuard<'a, 'key, T, Key, R>
{
@@ -36,6 +80,14 @@ impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock> Deref
}
}
+impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock> AsRef<T>
+ for RwLockReadGuard<'a, 'key, T, Key, R>
+{
+ fn as_ref(&self) -> &T {
+ self
+ }
+}
+
impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock>
RwLockReadGuard<'a, 'key, T, Key, R>
{
diff --git a/src/rwlock/read_lock.rs b/src/rwlock/read_lock.rs
index 176fc01..4f2bc86 100644
--- a/src/rwlock/read_lock.rs
+++ b/src/rwlock/read_lock.rs
@@ -6,7 +6,7 @@ use crate::key::Keyable;
use super::{ReadLock, RwLock, RwLockReadGuard, RwLockReadRef};
-impl<'a, T: ?Sized + Debug, R: RawRwLock> Debug for ReadLock<'a, T, R> {
+impl<'l, T: ?Sized + Debug, R: RawRwLock> Debug for ReadLock<'l, T, R> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// safety: this is just a try lock, and the value is dropped
// immediately after, so there's no risk of blocking ourselves
@@ -28,19 +28,19 @@ impl<'a, T: ?Sized + Debug, R: RawRwLock> Debug for ReadLock<'a, T, R> {
}
}
-impl<'a, T: ?Sized, R> From<&'a RwLock<T, R>> for ReadLock<'a, T, R> {
- fn from(value: &'a RwLock<T, R>) -> Self {
+impl<'l, T, R> From<&'l RwLock<T, R>> for ReadLock<'l, T, R> {
+ fn from(value: &'l RwLock<T, R>) -> Self {
Self::new(value)
}
}
-impl<'a, T: ?Sized, R> AsRef<RwLock<T, R>> for ReadLock<'a, T, R> {
+impl<'l, T: ?Sized, R> AsRef<RwLock<T, R>> for ReadLock<'l, T, R> {
fn as_ref(&self) -> &RwLock<T, R> {
self.0
}
}
-impl<'a, T: ?Sized, R> ReadLock<'a, T, R> {
+impl<'l, T, R> ReadLock<'l, T, R> {
/// Creates a new `ReadLock` which accesses the given [`RwLock`]
///
/// # Examples
@@ -52,12 +52,12 @@ impl<'a, T: ?Sized, R> ReadLock<'a, T, R> {
/// let read_lock = ReadLock::new(&lock);
/// ```
#[must_use]
- pub const fn new(rwlock: &'a RwLock<T, R>) -> Self {
+ pub const fn new(rwlock: &'l RwLock<T, R>) -> Self {
Self(rwlock)
}
}
-impl<'a, T: ?Sized, R: RawRwLock> ReadLock<'a, T, R> {
+impl<'l, T: ?Sized, R: RawRwLock> ReadLock<'l, T, R> {
/// Locks the underlying [`RwLock`] with shared read access, blocking the
/// current thread until it can be acquired.
pub fn lock<'s, 'key: 's, Key: Keyable + 'key>(
@@ -67,12 +67,6 @@ impl<'a, T: ?Sized, R: RawRwLock> ReadLock<'a, T, R> {
self.0.read(key)
}
- /// Creates a shared lock without a key. Locking this without exclusive
- /// access to the key is undefined behavior.
- pub(crate) unsafe fn lock_no_key(&self) -> RwLockReadRef<'_, T, R> {
- self.0.read_no_key()
- }
-
/// Attempts to acquire the underlying [`RwLock`] with shared read access
/// without blocking.
pub fn try_lock<'s, 'key: 's, Key: Keyable + 'key>(
@@ -88,7 +82,7 @@ impl<'a, T: ?Sized, R: RawRwLock> ReadLock<'a, T, R> {
self.0.try_read_no_key()
}
- /// Immediately drops the guard, and consequentlyreleases the shared lock
+ /// Immediately drops the guard, and consequently releases the shared lock
/// on the underlying [`RwLock`].
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
index dc5ab30..5bff5a3 100644
--- a/src/rwlock/rwlock.rs
+++ b/src/rwlock/rwlock.rs
@@ -5,7 +5,7 @@ use lock_api::RawRwLock;
use crate::key::Keyable;
-use super::{RwLock, RwLockReadGuard, RwLockReadRef, RwLockWriteGuard, RwLockWriteRef};
+use super::{RwLock, RwLockReadGuard, RwLockReadRef, RwLockWriteGuard};
impl<T, R: RawRwLock> RwLock<T, R> {
/// Creates a new instance of an `RwLock<T>` which is unlocked.
@@ -24,11 +24,19 @@ impl<T, R: RawRwLock> RwLock<T, R> {
raw: R::INIT,
}
}
-}
-impl<T: ?Sized + Default, R: RawRwLock> Default for RwLock<T, R> {
- fn default() -> Self {
- Self::new(T::default())
+ /// Returns the underlying raw reader-writer lock object.
+ ///
+ /// Note that you will most likely need to import the [`RawRwLock`] trait
+ /// from `lock_api` to be able to call functions on the raw reader-writer
+ /// lock.
+ ///
+ /// # Safety
+ ///
+ /// This method is unsafe because it allows unlocking a mutex while
+ /// still holding a reference to a lock guard.
+ pub const unsafe fn raw(&self) -> &R {
+ &self.raw
}
}
@@ -54,6 +62,12 @@ impl<T: ?Sized + Debug, R: RawRwLock> Debug for RwLock<T, R> {
}
}
+impl<T: ?Sized + Default, R: RawRwLock> Default for RwLock<T, R> {
+ fn default() -> Self {
+ Self::new(T::default())
+ }
+}
+
impl<T, R: RawRwLock> From<T> for RwLock<T, R> {
fn from(value: T) -> Self {
Self::new(value)
@@ -62,7 +76,7 @@ impl<T, R: RawRwLock> From<T> for RwLock<T, R> {
impl<T: ?Sized, R> AsMut<T> for RwLock<T, R> {
fn as_mut(&mut self) -> &mut T {
- self.get_mut()
+ self.data.get_mut()
}
}
@@ -82,32 +96,12 @@ impl<T, R> RwLock<T, R> {
/// }
/// assert_eq!(lock.into_inner(), "modified");
/// ```
+ #[must_use]
pub fn into_inner(self) -> T {
self.data.into_inner()
}
}
-impl<T: ?Sized, R> RwLock<T, R> {
- /// Returns a mutable reference to the underlying data.
- ///
- /// Since this call borrows the `RwLock` mutably, no actual locking needs
- /// to take place. The mutable borrow statically guarantees no locks exist.
- ///
- /// # Examples
- ///
- /// ```
- /// use happylock::{RwLock, ThreadKey};
- ///
- /// let key = ThreadKey::get().unwrap();
- /// let mut lock = RwLock::new(0);
- /// *lock.get_mut() = 10;
- /// assert_eq!(*lock.read(key), 10);
- /// ```
- pub fn get_mut(&mut self) -> &mut T {
- self.data.get_mut()
- }
-}
-
impl<T: ?Sized, R: RawRwLock> RwLock<T, R> {
/// Locks this `RwLock` with shared read access, blocking the current
/// thread until it can be acquired.
@@ -155,15 +149,6 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> {
}
}
- /// Creates a shared lock without a key. Locking this without exclusive
- /// access to the key is undefined behavior.
- pub(crate) unsafe fn read_no_key(&self) -> RwLockReadRef<'_, T, R> {
- self.raw.lock_shared();
-
- // safety: the lock is locked first
- RwLockReadRef(self, PhantomData)
- }
-
/// Attempts to acquire this `RwLock` with shared read access without
/// blocking.
///
@@ -246,19 +231,10 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> {
}
}
- /// Creates an exclusive lock without a key. Locking this without exclusive
- /// access to the key is undefined behavior.
- pub(crate) unsafe fn write_no_key(&self) -> RwLockWriteRef<'_, T, R> {
- self.raw.lock_exclusive();
-
- // safety: the lock is locked first
- RwLockWriteRef(self, PhantomData)
- }
-
/// Attempts to lock this `RwLock` with exclusive write access.
///
/// This function does not block. If the lock could not be acquired at this
- /// time, then `None` is returned. Otherwise an RAII guard is returned
+ /// time, then `None` is returned. Otherwise, an RAII guard is returned
/// which will release the lock when it is dropped.
///
/// This function does not provide any guarantees with respect to the
@@ -290,17 +266,6 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> {
}
}
- /// Attempts to create an exclusive lock without a key. Locking this
- /// without exclusive access to the key is undefined behavior.
- 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, PhantomData))
- } else {
- None
- }
- }
-
/// Unlocks shared access on the `RwLock`. This is undefined behavior is
/// the data is still accessible.
pub(super) unsafe fn force_unlock_read(&self) {
diff --git a/src/rwlock/write_guard.rs b/src/rwlock/write_guard.rs
index 6549822..5b41c99 100644
--- a/src/rwlock/write_guard.rs
+++ b/src/rwlock/write_guard.rs
@@ -27,6 +27,18 @@ impl<'a, T: ?Sized + 'a, R: RawRwLock> DerefMut for RwLockWriteRef<'a, T, R> {
}
}
+impl<'a, T: ?Sized + 'a, R: RawRwLock> AsRef<T> for RwLockWriteRef<'a, T, R> {
+ fn as_ref(&self) -> &T {
+ self
+ }
+}
+
+impl<'a, T: ?Sized + 'a, R: RawRwLock> AsMut<T> for RwLockWriteRef<'a, T, R> {
+ fn as_mut(&mut self) -> &mut T {
+ self
+ }
+}
+
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
@@ -35,6 +47,15 @@ impl<'a, T: ?Sized + 'a, R: RawRwLock> Drop for RwLockWriteRef<'a, T, R> {
}
}
+impl<'a, T: ?Sized + 'a, R: RawRwLock> RwLockWriteRef<'a, T, R> {
+ /// Creates a reference to the underlying data of an [`RwLock`] without
+ /// locking or taking ownership of the key.
+ #[must_use]
+ pub(crate) unsafe fn new(mutex: &'a RwLock<T, R>) -> Self {
+ Self(mutex, PhantomData)
+ }
+}
+
impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock> Deref
for RwLockWriteGuard<'a, 'key, T, Key, R>
{
@@ -53,6 +74,22 @@ impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock> DerefMut
}
}
+impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock> AsRef<T>
+ for RwLockWriteGuard<'a, 'key, T, Key, R>
+{
+ fn as_ref(&self) -> &T {
+ self
+ }
+}
+
+impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock> AsMut<T>
+ for RwLockWriteGuard<'a, 'key, T, Key, R>
+{
+ fn as_mut(&mut self) -> &mut T {
+ self
+ }
+}
+
impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock>
RwLockWriteGuard<'a, 'key, T, Key, R>
{
diff --git a/src/rwlock/write_lock.rs b/src/rwlock/write_lock.rs
index d7333ae..15eaacc 100644
--- a/src/rwlock/write_lock.rs
+++ b/src/rwlock/write_lock.rs
@@ -4,14 +4,16 @@ use lock_api::RawRwLock;
use crate::key::Keyable;
-use super::{RwLock, RwLockWriteGuard, RwLockWriteRef, WriteLock};
+use super::{RwLock, RwLockWriteGuard, WriteLock};
-impl<'a, T: ?Sized + Debug, R: RawRwLock> Debug for WriteLock<'a, T, R> {
+impl<'l, T: ?Sized + Debug, R: RawRwLock> Debug for WriteLock<'l, T, R> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// safety: this is just a try lock, and the value is dropped
// immediately after, so there's no risk of blocking ourselves
// or any other threads
- if let Some(value) = unsafe { self.try_lock_no_key() } {
+ // It makes zero sense to try using an exclusive lock for this, so this
+ // is the only time when WriteLock does a read.
+ if let Some(value) = unsafe { self.0.try_read_no_key() } {
f.debug_struct("WriteLock").field("data", &&*value).finish()
} else {
struct LockedPlaceholder;
@@ -21,26 +23,26 @@ impl<'a, T: ?Sized + Debug, R: RawRwLock> Debug for WriteLock<'a, T, R> {
}
}
- f.debug_struct("ReadLock")
+ f.debug_struct("WriteLock")
.field("data", &LockedPlaceholder)
.finish()
}
}
}
-impl<'a, T: ?Sized, R> From<&'a RwLock<T, R>> for WriteLock<'a, T, R> {
- fn from(value: &'a RwLock<T, R>) -> Self {
+impl<'l, T, R> From<&'l RwLock<T, R>> for WriteLock<'l, T, R> {
+ fn from(value: &'l RwLock<T, R>) -> Self {
Self::new(value)
}
}
-impl<'a, T: ?Sized, R> AsRef<RwLock<T, R>> for WriteLock<'a, T, R> {
+impl<'l, T: ?Sized, R> AsRef<RwLock<T, R>> for WriteLock<'l, T, R> {
fn as_ref(&self) -> &RwLock<T, R> {
self.0
}
}
-impl<'a, T: ?Sized, R> WriteLock<'a, T, R> {
+impl<'l, T, R> WriteLock<'l, T, R> {
/// Creates a new `WriteLock` which accesses the given [`RwLock`]
///
/// # Examples
@@ -52,12 +54,12 @@ impl<'a, T: ?Sized, R> WriteLock<'a, T, R> {
/// let write_lock = WriteLock::new(&lock);
/// ```
#[must_use]
- pub const fn new(rwlock: &'a RwLock<T, R>) -> Self {
+ pub const fn new(rwlock: &'l RwLock<T, R>) -> Self {
Self(rwlock)
}
}
-impl<'a, T: ?Sized, R: RawRwLock> WriteLock<'a, T, R> {
+impl<'l, T: ?Sized, R: RawRwLock> WriteLock<'l, T, R> {
/// Locks the underlying [`RwLock`] with exclusive write access, blocking
/// the current until it can be acquired.
pub fn lock<'s, 'key: 's, Key: Keyable + 'key>(
@@ -67,12 +69,6 @@ impl<'a, T: ?Sized, R: RawRwLock> WriteLock<'a, T, R> {
self.0.write(key)
}
- /// Creates an exclusive lock without a key. Locking this without exclusive
- /// access to the key is undefined behavior.
- pub(crate) unsafe fn lock_no_key(&self) -> RwLockWriteRef<'_, T, R> {
- self.0.write_no_key()
- }
-
/// Attempts to lock the underlying [`RwLock`] with exclusive write access.
pub fn try_lock<'s, 'key: 's, Key: Keyable + 'key>(
&'s self,
@@ -81,11 +77,8 @@ impl<'a, T: ?Sized, R: RawRwLock> WriteLock<'a, T, R> {
self.0.try_write(key)
}
- /// Attempts to create an exclusive lock without a key. Locking this
- /// without exclusive access to the key is undefined behavior.
- pub(crate) unsafe fn try_lock_no_key(&self) -> Option<RwLockWriteRef<'_, T, R>> {
- self.0.try_write_no_key()
- }
+ // There's no `try_lock_no_key`. Instead, `try_read_no_key` is called on
+ // the referenced `RwLock`.
/// Immediately drops the guard, and consequently releases the exclusive
/// lock.