summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMica White <botahamec@outlook.com>2024-03-10 18:13:20 -0400
committerMica White <botahamec@outlook.com>2024-03-10 18:13:20 -0400
commit0c519b6c7801aa6a085551c8e144f0336e615870 (patch)
tree19063baecb0b50266c654f4809101e856ee89082 /src
parent61d709c211132adcc5158ded77c17d690ad5f8da (diff)
Better librarification
Diffstat (limited to 'src')
-rw-r--r--src/collection.rs129
-rw-r--r--src/key.rs11
-rw-r--r--src/lib.rs9
-rw-r--r--src/lockable.rs79
-rw-r--r--src/mutex.rs29
-rw-r--r--src/rwlock.rs79
6 files changed, 275 insertions, 61 deletions
diff --git a/src/collection.rs b/src/collection.rs
index 34de620..1ee5956 100644
--- a/src/collection.rs
+++ b/src/collection.rs
@@ -1,7 +1,5 @@
-use std::{
- marker::PhantomData,
- ops::{Deref, DerefMut},
-};
+use std::marker::PhantomData;
+use std::ops::{Deref, DerefMut};
use crate::{
key::Keyable,
@@ -9,6 +7,7 @@ use crate::{
};
/// 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() {
@@ -26,6 +25,7 @@ fn contains_duplicates(l: &[usize]) -> bool {
/// This could be a tuple of [`Lockable`] types, an array, or a `Vec`. But it
/// can be safely locked without causing a deadlock. To do this, it is very
/// important that no duplicate locks are included within.
+#[derive(Debug, Clone, Copy)]
pub struct LockCollection<L> {
collection: L,
}
@@ -37,15 +37,81 @@ pub struct LockGuard<'a, 'key: 'a, L: Lockable<'a>, Key: Keyable + 'key> {
_phantom: PhantomData<&'key ()>,
}
-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.
- pub const unsafe fn new_unchecked(collection: L) -> Self {
- Self { collection }
+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)
}
}
@@ -54,6 +120,7 @@ impl<'a, L: OwnedLockable<'a>> LockCollection<L> {
///
/// 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 }
}
@@ -62,11 +129,25 @@ impl<'a, L: OwnedLockable<'a>> LockCollection<L> {
///
/// 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.
///
@@ -78,6 +159,7 @@ impl<'a, L: Lockable<'a>> LockCollection<L> {
/// 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) {
@@ -123,6 +205,27 @@ impl<'a, L: Lockable<'a>> LockCollection<L> {
}
}
+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;
diff --git a/src/key.rs b/src/key.rs
index 0297bc1..d951154 100644
--- a/src/key.rs
+++ b/src/key.rs
@@ -6,9 +6,10 @@ use once_cell::sync::Lazy;
use thread_local::ThreadLocal;
use self::sealed::Sealed;
+use super::ThreadKey;
mod sealed {
- use super::ThreadKey;
+ use crate::ThreadKey;
pub trait Sealed {}
impl Sealed for ThreadKey {}
impl Sealed for &mut ThreadKey {}
@@ -16,12 +17,7 @@ mod sealed {
static KEY: Lazy<ThreadLocal<AtomicLock>> = Lazy::new(ThreadLocal::new);
-/// The key for the current thread.
-///
-/// Only one of these exist per thread. To get the current thread's key, call
-/// [`ThreadKey::lock`]. If the `ThreadKey` is dropped, it can be reobtained.
-pub type ThreadKey = Key<'static>;
-
+/// A key that can be obtained and dropped
pub struct Key<'a> {
phantom: PhantomData<*const ()>, // implement !Send and !Sync
lock: &'a AtomicLock,
@@ -85,6 +81,7 @@ impl AtomicLock {
///
/// This is not a fair lock. It is not recommended to call this function
/// repeatedly in a loop.
+ #[must_use]
pub fn try_lock(&self) -> Option<Key> {
// safety: we just acquired the lock
(!self.is_locked.swap(true, Ordering::Acquire)).then_some(Key {
diff --git a/src/lib.rs b/src/lib.rs
index 25b6d03..e99db7c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -5,17 +5,22 @@
#![allow(clippy::semicolon_if_nothing_returned)]
mod collection;
-mod key;
mod lockable;
+pub mod key;
pub mod mutex;
pub mod rwlock;
pub use collection::LockCollection;
-pub use key::{Key, ThreadKey};
pub use lockable::Lockable;
pub use mutex::SpinLock;
+/// The key for the current thread.
+///
+/// Only one of these exist per thread. To get the current thread's key, call
+/// [`ThreadKey::lock`]. If the `ThreadKey` is dropped, it can be reobtained.
+pub type ThreadKey = key::Key<'static>;
+
/// A mutual exclusion primitive useful for protecting shared data, which cannot deadlock.
///
/// By default, this uses `parking_lot` as a backend.
diff --git a/src/lockable.rs b/src/lockable.rs
index 3c217c4..d3367fa 100644
--- a/src/lockable.rs
+++ b/src/lockable.rs
@@ -7,28 +7,6 @@ use crate::{
use lock_api::{RawMutex, RawRwLock};
-mod sealed {
- use super::Lockable as L;
- #[allow(clippy::wildcard_imports)]
- use super::*;
-
- pub trait Sealed {}
- impl<'a, T, R: RawMutex + 'a> Sealed for Mutex<T, R> {}
- impl<'a, T, R: RawRwLock + 'a> Sealed for RwLock<T, R> {}
- impl<'a, T, R: RawRwLock + 'a> Sealed for ReadLock<'a, T, R> {}
- impl<'a, T, R: RawRwLock + 'a> Sealed for WriteLock<'a, T, R> {}
- impl<T: Sealed> Sealed for &T {}
- impl<T: Sealed> Sealed for &mut T {}
- impl<'a, A: L<'a>> Sealed for (A,) {}
- impl<'a, A: L<'a>, B: L<'a>> Sealed for (A, B) {}
- impl<'a, A: L<'a>, B: L<'a>, C: L<'a>> Sealed for (A, B, C) {}
- impl<'a, A: L<'a>, B: L<'a>, C: L<'a>, D: L<'a>> Sealed for (A, B, C, D) {}
- impl<'a, A: L<'a>, B: L<'a>, C: L<'a>, D: L<'a>, E: L<'a>> Sealed for (A, B, C, D, E) {}
- impl<'a, A: L<'a>, B: L<'a>, C: L<'a>, D: L<'a>, E: L<'a>, F: L<'a>> Sealed for (A, B, C, D, E, F) {}
- impl<'a, T: Lockable<'a>, const N: usize> Sealed for [T; N] {}
- impl<'a, T: Lockable<'a>> Sealed for Vec<T> {}
-}
-
/// A type that may be locked and unlocked, and is known to be the only valid
/// instance of the lock.
///
@@ -45,12 +23,13 @@ pub unsafe trait OwnedLockable<'a>: Lockable<'a> {}
/// A deadlock must never occur. The `unlock` method must correctly unlock the
/// data. The `get_ptrs` method must be implemented correctly. The `Output`
/// must be unlocked when it is dropped.
-pub unsafe trait Lockable<'a>: sealed::Sealed {
+pub unsafe trait Lockable<'a> {
/// The output of the lock
type Output;
/// Returns a list of all pointers to locks. This is used to ensure that
/// the same lock isn't included twice
+ #[must_use]
fn get_ptrs(&self) -> Vec<usize>;
/// Blocks until the lock is acquired
@@ -62,7 +41,7 @@ pub unsafe trait Lockable<'a>: sealed::Sealed {
/// which should last as long as the return value is alive.
/// * Call this on multiple locks without unlocking first.
///
- /// [`ThreadKey`]: `crate::key::ThreadKey`
+ /// [`ThreadKey`]: `crate::ThreadKey`
unsafe fn lock(&'a self) -> Self::Output;
/// Attempt to lock without blocking.
@@ -75,7 +54,7 @@ pub unsafe trait Lockable<'a>: sealed::Sealed {
/// access to the [`ThreadKey`], which should last as long as the return
/// value is alive.
///
- /// [`ThreadKey`]: `crate::key::ThreadKey`
+ /// [`ThreadKey`]: `crate::ThreadKey`
unsafe fn try_lock(&'a self) -> Option<Self::Output>;
}
@@ -153,7 +132,7 @@ unsafe impl<'a, T: 'a, R: RawRwLock + 'a> Lockable<'a> for ReadLock<'a, T, R> {
type Output = RwLockReadRef<'a, T, R>;
fn get_ptrs(&self) -> Vec<usize> {
- vec![self.0 as *const RwLock<T, R> as usize]
+ vec![self.as_ref() as *const RwLock<T, R> as usize]
}
unsafe fn lock(&'a self) -> Self::Output {
@@ -169,7 +148,7 @@ unsafe impl<'a, T: 'a, R: RawRwLock + 'a> Lockable<'a> for WriteLock<'a, T, R> {
type Output = RwLockWriteRef<'a, T, R>;
fn get_ptrs(&self) -> Vec<usize> {
- vec![self.0 as *const RwLock<T, R> as usize]
+ vec![self.as_ref() as *const RwLock<T, R> as usize]
}
unsafe fn lock(&'a self) -> Self::Output {
@@ -562,6 +541,51 @@ unsafe impl<'a, T: Lockable<'a>, const N: usize> Lockable<'a> for [T; N] {
}
}
+unsafe impl<'a, T: Lockable<'a>> Lockable<'a> for Box<[T]> {
+ type Output = Box<[T::Output]>;
+
+ fn get_ptrs(&self) -> Vec<usize> {
+ let mut ptrs = Vec::with_capacity(self.len());
+ for lock in &**self {
+ ptrs.append(&mut lock.get_ptrs());
+ }
+ ptrs
+ }
+
+ unsafe fn lock(&'a self) -> Self::Output {
+ 'outer: loop {
+ let mut outputs = Vec::with_capacity(self.len());
+ if self.is_empty() {
+ return outputs.into_boxed_slice();
+ }
+
+ outputs.push(self[0].lock());
+ for lock in self.iter().skip(1) {
+ if let Some(guard) = lock.try_lock() {
+ outputs.push(guard);
+ } else {
+ continue 'outer;
+ };
+ }
+
+ return outputs.into_boxed_slice();
+ }
+ }
+
+ unsafe fn try_lock(&'a self) -> Option<Self::Output> {
+ let mut outputs = Vec::with_capacity(self.len());
+ for lock in &**self {
+ if let Some(guard) = lock.try_lock() {
+ outputs.push(guard);
+ } else {
+ return None;
+ };
+ }
+
+ Some(outputs.into_boxed_slice())
+ }
+}
+
unsafe impl<'a, T: Lockable<'a>> Lockable<'a> for Vec<T> {
type Output = Vec<T::Output>;
@@ -608,4 +632,5 @@ unsafe impl<'a, T: Lockable<'a>> Lockable<'a> for Vec<T> {
}
unsafe impl<'a, T: OwnedLockable<'a>, const N: usize> OwnedLockable<'a> for [T; N] {}
+unsafe impl<'a, T: OwnedLockable<'a>> OwnedLockable<'a> for Box<[T]> {}
unsafe impl<'a, T: OwnedLockable<'a>> OwnedLockable<'a> for Vec<T> {}
diff --git a/src/mutex.rs b/src/mutex.rs
index c78d398..e7a439c 100644
--- a/src/mutex.rs
+++ b/src/mutex.rs
@@ -1,4 +1,5 @@
use std::cell::UnsafeCell;
+use std::fmt::Debug;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
@@ -97,6 +98,7 @@ impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawMutex> DerefMut
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),
@@ -116,6 +118,7 @@ impl<T, R: RawMutex> Mutex<T, R> {
///
/// let mutex = Mutex::new(0);
/// ```
+ #[must_use]
pub const fn new(value: T) -> Self {
Self {
raw: R::INIT,
@@ -124,6 +127,24 @@ impl<T, R: RawMutex> Mutex<T, R> {
}
}
+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.
///
@@ -134,7 +155,8 @@ impl<T, R> Mutex<T, R> {
///
/// let mutex = Mutex::new(0);
/// assert_eq!(mutex.into_inner(), 0);
- /// ````
+ /// ```
+ #[must_use]
pub fn into_inner(self) -> T {
self.value.into_inner()
}
@@ -155,7 +177,8 @@ impl<T: ?Sized, R> Mutex<T, R> {
/// 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()
}
@@ -283,4 +306,4 @@ impl<T: ?Sized, R: RawMutex> Mutex<T, R> {
}
unsafe impl<R: RawMutex + Send, T: ?Sized + Send> Send for Mutex<T, R> {}
-unsafe impl<R: RawMutex + Sync, T: ?Sized + Send> Sync for Mutex<T, R> {}
+unsafe impl<R: RawMutex + Sync, T: ?Sized + Send + Sync> Sync for Mutex<T, R> {}
diff --git a/src/rwlock.rs b/src/rwlock.rs
index 722ca2f..f5f0f2b 100644
--- a/src/rwlock.rs
+++ b/src/rwlock.rs
@@ -1,8 +1,7 @@
-use std::{
- cell::UnsafeCell,
- marker::PhantomData,
- ops::{Deref, DerefMut},
-};
+use std::cell::UnsafeCell;
+use std::fmt::Debug;
+use std::marker::PhantomData;
+use std::ops::{Deref, DerefMut};
use lock_api::RawRwLock;
@@ -17,9 +16,9 @@ pub struct RwLock<T: ?Sized, R> {
value: UnsafeCell<T>,
}
-pub struct ReadLock<'a, T: ?Sized, R>(pub(crate) &'a RwLock<T, R>);
+pub struct ReadLock<'a, T: ?Sized, R>(&'a RwLock<T, R>);
-pub struct WriteLock<'a, T: ?Sized, R>(pub(crate) &'a RwLock<T, R>);
+pub struct WriteLock<'a, T: ?Sized, R>(&'a RwLock<T, R>);
pub struct RwLockReadRef<'a, T: ?Sized, R: RawRwLock>(&'a RwLock<T, R>);
@@ -37,6 +36,9 @@ pub struct RwLockWriteGuard<'a, 'key, T: ?Sized, Key: Keyable + 'key, R: RawRwLo
_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;
@@ -117,6 +119,7 @@ impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock>
{
/// 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),
@@ -131,6 +134,7 @@ impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock>
{
/// 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),
@@ -141,6 +145,7 @@ impl<'a, 'key: 'a, T: ?Sized + 'a, Key: Keyable, R: RawRwLock>
}
impl<T, R: RawRwLock> RwLock<T, R> {
+ #[must_use]
pub const fn new(value: T) -> Self {
Self {
value: UnsafeCell::new(value),
@@ -149,6 +154,60 @@ impl<T, R: RawRwLock> RwLock<T, R> {
}
}
+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()
@@ -273,7 +332,8 @@ impl<T: ?Sized, R: RawRwLock> RwLock<T, R> {
}
}
-impl<'a, T, R> ReadLock<'a, T, R> {
+impl<'a, T: ?Sized, R> ReadLock<'a, T, R> {
+ #[must_use]
pub const fn new(rwlock: &'a RwLock<T, R>) -> Self {
Self(rwlock)
}
@@ -307,7 +367,8 @@ impl<'a, T: ?Sized, R: RawRwLock> ReadLock<'a, T, R> {
}
}
-impl<'a, T, R> WriteLock<'a, T, R> {
+impl<'a, T: ?Sized, R> WriteLock<'a, T, R> {
+ #[must_use]
pub const fn new(rwlock: &'a RwLock<T, R>) -> Self {
Self(rwlock)
}