diff options
| author | Botahamec <botahamec@outlook.com> | 2024-05-21 19:17:11 -0400 |
|---|---|---|
| committer | Botahamec <botahamec@outlook.com> | 2024-05-21 19:17:11 -0400 |
| commit | 86610b631c20832d160c1a38181080232a05b508 (patch) | |
| tree | d10eaefdf7ecaa6add29c87ed4be77e231b8bfd1 /src | |
| parent | cf49f2900fe3c7abd1bbadacfdc745d6b5bbc235 (diff) | |
Sharable API
Diffstat (limited to 'src')
| -rw-r--r-- | src/collection.rs | 19 | ||||
| -rw-r--r-- | src/collection/boxed.rs (renamed from src/collection/boxed_collection.rs) | 12 | ||||
| -rw-r--r-- | src/collection/guard.rs | 8 | ||||
| -rw-r--r-- | src/collection/owned.rs | 158 | ||||
| -rw-r--r-- | src/collection/owned_collection.rs | 65 | ||||
| -rw-r--r-- | src/collection/ref.rs (renamed from src/collection/ref_collection.rs) | 31 | ||||
| -rw-r--r-- | src/collection/retry.rs | 271 | ||||
| -rw-r--r-- | src/collection/retry_collection.rs | 138 | ||||
| -rw-r--r-- | src/lib.rs | 3 | ||||
| -rw-r--r-- | src/lockable.rs | 235 |
10 files changed, 711 insertions, 229 deletions
diff --git a/src/collection.rs b/src/collection.rs index a11d60c..6623c8a 100644 --- a/src/collection.rs +++ b/src/collection.rs @@ -1,15 +1,12 @@ use std::marker::PhantomData; -use crate::{ - key::Keyable, - lockable::{Lock, Lockable}, -}; +use crate::{key::Keyable, lockable::Lock}; -mod boxed_collection; +mod boxed; mod guard; -mod owned_collection; -mod ref_collection; -mod retry_collection; +mod owned; +mod r#ref; +mod retry; pub struct OwnedLockCollection<L> { data: L, @@ -24,15 +21,15 @@ pub struct RefLockCollection<'a, L> { data: &'a L, } -pub struct BoxedLockCollection<'a, L>(RefLockCollection<'a, L>); +pub struct BoxedLockCollection<'a, L: 'a>(RefLockCollection<'a, L>); pub struct RetryingLockCollection<L> { data: L, } /// A RAII guard for a generic [`Lockable`] type. -pub struct LockGuard<'g, 'key: 'g, L: Lockable + 'g, Key: Keyable + 'key> { - guard: L::Guard<'g>, +pub struct LockGuard<'key, Guard, Key: Keyable + 'key> { + guard: Guard, key: Key, _phantom: PhantomData<&'key ()>, } diff --git a/src/collection/boxed_collection.rs b/src/collection/boxed.rs index 1aae1e4..8b67ee9 100644 --- a/src/collection/boxed_collection.rs +++ b/src/collection/boxed.rs @@ -4,7 +4,7 @@ use crate::{Lockable, OwnedLockable}; use super::{BoxedLockCollection, RefLockCollection}; -impl<'a, L> Deref for BoxedLockCollection<'a, L> { +impl<'a, L: 'a> Deref for BoxedLockCollection<'a, L> { type Target = RefLockCollection<'a, L>; fn deref(&self) -> &Self::Target { @@ -12,13 +12,13 @@ impl<'a, L> Deref for BoxedLockCollection<'a, L> { } } -impl<'a, L> DerefMut for BoxedLockCollection<'a, L> { +impl<'a, L: 'a> DerefMut for BoxedLockCollection<'a, L> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } -impl<'a, L> Drop for BoxedLockCollection<'a, L> { +impl<'a, L: 'a> Drop for BoxedLockCollection<'a, L> { fn drop(&mut self) { // this was created with Box::new let boxed = unsafe { Box::from_raw((self.0.data as *const L).cast_mut()) }; @@ -26,7 +26,7 @@ impl<'a, L> Drop for BoxedLockCollection<'a, L> { } } -impl<'a, L: OwnedLockable> BoxedLockCollection<'a, L> { +impl<'a, L: OwnedLockable + 'a> BoxedLockCollection<'a, L> { #[must_use] pub fn new(data: L) -> Self { let boxed = Box::leak(Box::new(data)); @@ -34,7 +34,7 @@ impl<'a, L: OwnedLockable> BoxedLockCollection<'a, L> { } } -impl<'a, L: OwnedLockable> BoxedLockCollection<'a, &'a L> { +impl<'a, L: OwnedLockable + 'a> BoxedLockCollection<'a, L> { #[must_use] pub fn new_ref(data: &'a L) -> Self { let boxed = Box::leak(Box::new(data)); @@ -45,7 +45,7 @@ impl<'a, L: OwnedLockable> BoxedLockCollection<'a, &'a L> { } } -impl<'a, L: Lockable> BoxedLockCollection<'a, L> { +impl<'a, L: Lockable + 'a> BoxedLockCollection<'a, L> { #[must_use] pub unsafe fn new_unchecked(data: L) -> Self { let boxed = Box::leak(Box::new(data)); diff --git a/src/collection/guard.rs b/src/collection/guard.rs index e3ffb21..b8561eb 100644 --- a/src/collection/guard.rs +++ b/src/collection/guard.rs @@ -1,18 +1,18 @@ use std::ops::{Deref, DerefMut}; -use crate::{key::Keyable, Lockable}; +use crate::key::Keyable; use super::LockGuard; -impl<'a, 'key: 'a, L: Lockable + 'a, Key: Keyable> Deref for LockGuard<'a, 'key, L, Key> { - type Target = L::Guard<'a>; +impl<'key, Guard, Key: Keyable> Deref for LockGuard<'key, Guard, Key> { + type Target = Guard; fn deref(&self) -> &Self::Target { &self.guard } } -impl<'a, 'key: 'a, L: Lockable + 'a, Key: Keyable> DerefMut for LockGuard<'a, 'key, L, Key> { +impl<'key, Guard, Key: Keyable> DerefMut for LockGuard<'key, Guard, Key> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.guard } diff --git a/src/collection/owned.rs b/src/collection/owned.rs new file mode 100644 index 0000000..3415ac4 --- /dev/null +++ b/src/collection/owned.rs @@ -0,0 +1,158 @@ +use std::marker::PhantomData; + +use crate::{lockable::Lock, Keyable, Lockable, OwnedLockable, Sharable}; + +use super::{LockGuard, OwnedLockCollection}; + +fn get_locks<L: Lockable>(data: &L) -> Vec<&dyn Lock> { + let mut locks = Vec::new(); + data.get_ptrs(&mut locks); + locks +} + +unsafe impl<L: Lockable> Lockable for OwnedLockCollection<L> { + type Guard<'g> = L::Guard<'g> where Self: 'g; + + type ReadGuard<'g> = L::ReadGuard<'g> where Self: 'g; + + fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn Lock>) { + self.data.get_ptrs(ptrs) + } + + unsafe fn guard(&self) -> Self::Guard<'_> { + self.data.guard() + } + + unsafe fn read_guard(&self) -> Self::ReadGuard<'_> { + self.data.read_guard() + } +} + +unsafe impl<L: Sharable> Sharable for OwnedLockCollection<L> {} + +unsafe impl<L: OwnedLockable> OwnedLockable for OwnedLockCollection<L> {} + +impl<L: OwnedLockable> OwnedLockCollection<L> { + #[must_use] + pub const fn new(data: L) -> Self { + Self { data } + } + + pub fn lock<'g, 'key, Key: Keyable + 'key>( + &'g self, + key: Key, + ) -> LockGuard<'key, L::Guard<'g>, Key> { + let locks = get_locks(&self.data); + for lock in locks { + // safety: we have the thread key, and these locks happen in a + // predetermined order + unsafe { lock.lock() }; + } + + // safety: we've locked all of this already + let guard = unsafe { self.data.guard() }; + LockGuard { + guard, + key, + _phantom: PhantomData, + } + } + + pub fn try_lock<'g, 'key: 'g, Key: Keyable + 'key>( + &'g self, + key: Key, + ) -> Option<LockGuard<'key, L::Guard<'g>, Key>> { + let locks = get_locks(&self.data); + let guard = unsafe { + for (i, lock) in locks.iter().enumerate() { + // safety: we have the thread key + let success = lock.try_lock(); + + if !success { + for lock in &locks[0..i] { + // safety: this lock was already acquired + lock.unlock(); + } + return None; + } + } + + // safety: we've acquired the locks + self.data.guard() + }; + + Some(LockGuard { + guard, + key, + _phantom: PhantomData, + }) + } + + #[allow(clippy::missing_const_for_fn)] + pub fn unlock<'g, 'key: 'g, Key: Keyable + 'key>( + guard: LockGuard<'key, L::Guard<'g>, Key>, + ) -> Key { + drop(guard.guard); + guard.key + } +} + +impl<L: Sharable> OwnedLockCollection<L> { + pub fn read<'g, 'key, Key: Keyable + 'key>( + &'g self, + key: Key, + ) -> LockGuard<'key, L::ReadGuard<'g>, Key> { + let locks = get_locks(&self.data); + for lock in locks { + // safety: we have the thread key, and these locks happen in a + // predetermined order + unsafe { lock.read() }; + } + + // safety: we've locked all of this already + let guard = unsafe { self.data.read_guard() }; + LockGuard { + guard, + key, + _phantom: PhantomData, + } + } + + pub fn try_read<'g, 'key: 'g, Key: Keyable + 'key>( + &'g self, + key: Key, + ) -> Option<LockGuard<'key, L::ReadGuard<'g>, Key>> { + let locks = get_locks(&self.data); + let guard = unsafe { + for (i, lock) in locks.iter().enumerate() { + // safety: we have the thread key + let success = lock.try_read(); + + if !success { + for lock in &locks[0..i] { + // safety: this lock was already acquired + lock.unlock(); + } + return None; + } + } + + // safety: we've acquired the locks + self.data.read_guard() + }; + + Some(LockGuard { + guard, + key, + _phantom: PhantomData, + }) + } + + #[allow(clippy::missing_const_for_fn)] + pub fn unlock_read<'g, 'key: 'g, Key: Keyable + 'key>( + guard: LockGuard<'key, L::ReadGuard<'g>, Key>, + ) -> Key { + drop(guard.guard); + guard.key + } +} diff --git a/src/collection/owned_collection.rs b/src/collection/owned_collection.rs deleted file mode 100644 index ea8f2f2..0000000 --- a/src/collection/owned_collection.rs +++ /dev/null @@ -1,65 +0,0 @@ -use std::marker::PhantomData; - -use crate::{lockable::Lock, Keyable, Lockable, OwnedLockable}; - -use super::{LockGuard, OwnedLockCollection}; - -fn get_locks<L: Lockable>(data: &L) -> Vec<&dyn Lock> { - let mut locks = Vec::new(); - data.get_ptrs(&mut locks); - locks -} - -impl<L: OwnedLockable> OwnedLockCollection<L> { - #[must_use] - pub const fn new(data: L) -> Self { - Self { data } - } - - pub fn lock<'a, 'key, Key: Keyable + 'key>(&'a self, key: Key) -> LockGuard<'a, 'key, L, Key> { - let locks = get_locks(&self.data); - for lock in locks { - // safety: we have the thread key, and these locks happen in a - // predetermined order - unsafe { lock.lock() }; - } - - // safety: we've locked all of this already - let guard = unsafe { self.data.guard() }; - LockGuard { - guard, - key, - _phantom: PhantomData, - } - } - - pub fn try_lock<'a, 'key: 'a, Key: Keyable + 'key>( - &'a self, - key: Key, - ) -> Option<LockGuard<'a, 'key, L, Key>> { - let locks = get_locks(&self.data); - let guard = unsafe { - for (i, lock) in locks.iter().enumerate() { - // safety: we have the thread key - let success = lock.try_lock(); - - if !success { - for lock in &locks[0..i] { - // safety: this lock was already acquired - lock.unlock(); - } - return None; - } - } - - // safety: we've acquired the locks - self.data.guard() - }; - - Some(LockGuard { - guard, - key, - _phantom: PhantomData, - }) - } -} diff --git a/src/collection/ref_collection.rs b/src/collection/ref.rs index 41f6b16..9fe34c9 100644 --- a/src/collection/ref_collection.rs +++ b/src/collection/ref.rs @@ -1,6 +1,6 @@ use std::marker::PhantomData; -use crate::{key::Keyable, lockable::Lock, Lockable, OwnedLockable}; +use crate::{key::Keyable, lockable::Lock, Lockable, OwnedLockable, Sharable}; use super::{LockGuard, RefLockCollection}; @@ -49,6 +49,26 @@ where } } +unsafe impl<'c, L: Lockable> Lockable for RefLockCollection<'c, L> { + type Guard<'g> = L::Guard<'g> where Self: 'g; + + type ReadGuard<'g> = L::ReadGuard<'g> where Self: 'g; + + fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn Lock>) { + ptrs.extend_from_slice(&self.locks); + } + + unsafe fn guard(&self) -> Self::Guard<'_> { + self.data.guard() + } + + unsafe fn read_guard(&self) -> Self::ReadGuard<'_> { + self.data.read_guard() + } +} + +unsafe impl<'c, L: Sharable> Sharable for RefLockCollection<'c, L> {} + impl<'a, L: OwnedLockable> RefLockCollection<'a, L> { /// Creates a new collection of owned locks. /// @@ -143,7 +163,10 @@ impl<'a, L: Lockable> RefLockCollection<'a, L> { /// *guard.0 += 1; /// *guard.1 = "1"; /// ``` - pub fn lock<'key: 'a, Key: Keyable + 'key>(&'a self, key: Key) -> LockGuard<'a, 'key, L, Key> { + pub fn lock<'key: 'a, Key: Keyable + 'key>( + &'a self, + key: Key, + ) -> LockGuard<'key, L::Guard<'a>, Key> { for lock in &self.locks { // safety: we have the thread key unsafe { lock.lock() }; @@ -183,7 +206,7 @@ impl<'a, L: Lockable> RefLockCollection<'a, L> { pub fn try_lock<'key: 'a, Key: Keyable + 'key>( &'a self, key: Key, - ) -> Option<LockGuard<'a, 'key, L, Key>> { + ) -> Option<LockGuard<'key, L::Guard<'a>, Key>> { let guard = unsafe { for (i, lock) in self.locks.iter().enumerate() { // safety: we have the thread key @@ -226,7 +249,7 @@ impl<'a, L: Lockable> RefLockCollection<'a, L> { /// let key = LockCollection::unlock(guard); /// ``` #[allow(clippy::missing_const_for_fn)] - pub fn unlock<'key: 'a, Key: Keyable + 'key>(guard: LockGuard<'a, 'key, L, Key>) -> Key { + pub fn unlock<'key: 'a, Key: Keyable + 'key>(guard: LockGuard<'key, L::Guard<'a>, Key>) -> Key { drop(guard.guard); guard.key } diff --git a/src/collection/retry.rs b/src/collection/retry.rs new file mode 100644 index 0000000..3000f8b --- /dev/null +++ b/src/collection/retry.rs @@ -0,0 +1,271 @@ +use crate::{lockable::Lock, Keyable, Lockable, OwnedLockable, Sharable}; +use std::collections::HashSet; +use std::marker::PhantomData; + +use super::{LockGuard, RetryingLockCollection}; + +fn contains_duplicates<L: Lockable>(data: L) -> bool { + let mut locks = Vec::new(); + data.get_ptrs(&mut locks); + let locks = locks.into_iter().map(|l| l as *const dyn Lock); + + let mut locks_set = HashSet::new(); + for lock in locks { + if !locks_set.insert(lock) { + return true; + } + } + + false +} + +unsafe impl<L: Lockable> Lockable for RetryingLockCollection<L> { + type Guard<'g> = L::Guard<'g> where Self: 'g; + + type ReadGuard<'g> = L::ReadGuard<'g> where Self: 'g; + + fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn Lock>) { + self.data.get_ptrs(ptrs) + } + + unsafe fn guard(&self) -> Self::Guard<'_> { + self.data.guard() + } + + unsafe fn read_guard(&self) -> Self::ReadGuard<'_> { + self.data.read_guard() + } +} + +unsafe impl<L: Sharable> Sharable for RetryingLockCollection<L> {} + +unsafe impl<L: OwnedLockable> OwnedLockable for RetryingLockCollection<L> {} + +impl<L: OwnedLockable> RetryingLockCollection<L> { + #[must_use] + pub const fn new(data: L) -> Self { + Self { data } + } +} + +impl<'a, L: OwnedLockable> RetryingLockCollection<&'a L> { + #[must_use] + pub const fn new_ref(data: &'a L) -> Self { + Self { data } + } +} + +impl<L: Lockable> RetryingLockCollection<L> { + #[must_use] + pub const unsafe fn new_unchecked(data: L) -> Self { + Self { data } + } + + pub fn try_new(data: L) -> Option<Self> { + contains_duplicates(&data).then_some(Self { data }) + } + + pub fn lock<'g, 'key: 'g, Key: Keyable + 'key>( + &'g self, + key: Key, + ) -> LockGuard<'key, L::Guard<'g>, Key> { + let mut first_index = 0; + let mut locks = Vec::new(); + self.data.get_ptrs(&mut locks); + + if locks.is_empty() { + return LockGuard { + // safety: there's no data being returned + guard: unsafe { self.data.guard() }, + key, + _phantom: PhantomData, + }; + } + + let guard = unsafe { + 'outer: loop { + // safety: we have the thread key + locks[first_index].lock(); + for (i, lock) in locks.iter().enumerate() { + if i == first_index { + continue; + } + + // safety: we have the thread key + if !lock.try_lock() { + for lock in locks.iter().take(i) { + // safety: we already locked all of these + lock.unlock(); + } + + if first_index >= i { + // safety: this is already locked and can't be unlocked + // by the previous loop + locks[first_index].unlock(); + } + + first_index = i; + continue 'outer; + } + } + + // safety: we locked all the data + break self.data.guard(); + } + }; + + LockGuard { + guard, + key, + _phantom: PhantomData, + } + } + + pub fn try_lock<'g, 'key: 'g, Key: Keyable + 'key>( + &'g self, + key: Key, + ) -> Option<LockGuard<'key, L::Guard<'g>, Key>> { + let mut locks = Vec::new(); + self.data.get_ptrs(&mut locks); + + if locks.is_empty() { + return Some(LockGuard { + // safety: there's no data being returned + guard: unsafe { self.data.guard() }, + key, + _phantom: PhantomData, + }); + } + + let guard = unsafe { + for (i, lock) in locks.iter().enumerate() { + // safety: we have the thread key + if !lock.try_lock() { + for lock in locks.iter().take(i) { + // safety: we already locked all of these + lock.unlock(); + } + return None; + } + } + + // safety: we locked all the data + self.data.guard() + }; + + Some(LockGuard { + guard, + key, + _phantom: PhantomData, + }) + } + + pub fn unlock<'key, Key: Keyable + 'key>(guard: LockGuard<'key, L::Guard<'_>, Key>) -> Key { + drop(guard.guard); + guard.key + } +} + +impl<L: Sharable> RetryingLockCollection<L> { + pub fn read<'g, 'key: 'g, Key: Keyable + 'key>( + &'g self, + key: Key, + ) -> LockGuard<'key, L::ReadGuard<'g>, Key> { + let mut first_index = 0; + let mut locks = Vec::new(); + self.data.get_ptrs(&mut locks); + + if locks.is_empty() { + return LockGuard { + // safety: there's no data being returned + guard: unsafe { self.data.read_guard() }, + key, + _phantom: PhantomData, + }; + } + + let guard = unsafe { + 'outer: loop { + // safety: we have the thread key + locks[first_index].read(); + for (i, lock) in locks.iter().enumerate() { + if i == first_index { + continue; + } + + // safety: we have the thread key + if !lock.try_read() { + for lock in locks.iter().take(i) { + // safety: we already locked all of these + lock.unlock_read(); + } + + if first_index >= i { + // safety: this is already locked and can't be unlocked + // by the previous loop + locks[first_index].unlock_read(); + } + + first_index = i; + continue 'outer; + } + } + + // safety: we locked all the data + break self.data.read_guard(); + } + }; + + LockGuard { + guard, + key, + _phantom: PhantomData, + } + } + + pub fn try_read<'g, 'key: 'g, Key: Keyable + 'key>( + &'g self, + key: Key, + ) -> Option<LockGuard<'key, L::ReadGuard<'g>, Key>> { + let mut locks = Vec::new(); + self.data.get_ptrs(&mut locks); + + if locks.is_empty() { + return Some(LockGuard { + // safety: there's no data being returned + guard: unsafe { self.data.read_guard() }, + key, + _phantom: PhantomData, + }); + } + + let guard = unsafe { + for (i, lock) in locks.iter().enumerate() { + // safety: we have the thread key + if !lock.try_read() { + for lock in locks.iter().take(i) { + // safety: we already locked all of these + lock.unlock_read(); + } + return None; + } + } + + // safety: we locked all the data + self.data.read_guard() + }; + + Some(LockGuard { + guard, + key, + _phantom: PhantomData, + }) + } + + pub fn unlock_read<'key, Key: Keyable + 'key>( + guard: LockGuard<'key, L::ReadGuard<'_>, Key>, + ) -> Key { + drop(guard.guard); + guard.key + } +} diff --git a/src/collection/retry_collection.rs b/src/collection/retry_collection.rs deleted file mode 100644 index 73f9e18..0000000 --- a/src/collection/retry_collection.rs +++ /dev/null @@ -1,138 +0,0 @@ -use std::marker::PhantomData; - -use crate::{lockable::Lock, Keyable, Lockable, OwnedLockable}; - -use super::{LockGuard, RetryingLockCollection}; - -fn contains_duplicates<L: Lockable>(data: L) -> bool { - let mut locks = Vec::new(); - data.get_ptrs(&mut locks); - let mut locks: Vec<_> = locks.into_iter().map(|l| l as *const dyn Lock).collect(); - locks.sort_unstable(); - locks.windows(2).any(|w| std::ptr::addr_eq(w[0], w[1])) -} - -impl<L: OwnedLockable> RetryingLockCollection<L> { - #[must_use] - pub const fn new(data: L) -> Self { - Self { data } - } -} - -impl<'a, L: OwnedLockable> RetryingLockCollection<&'a L> { - #[must_use] - pub const fn new_ref(data: &'a L) -> Self { - Self { data } - } -} - -impl<L: Lockable> RetryingLockCollection<L> { - #[must_use] - pub const unsafe fn new_unchecked(data: L) -> Self { - Self { data } - } - - pub fn try_new(data: L) -> Option<Self> { - contains_duplicates(&data).then_some(Self { data }) - } - - pub fn lock<'a, 'key: 'a, Key: Keyable + 'key>( - &'a self, - key: Key, - ) -> LockGuard<'a, 'key, L, Key> { - let mut first_index = 0; - let mut locks = Vec::new(); - self.data.get_ptrs(&mut locks); - - if locks.is_empty() { - return LockGuard { - // safety: there's no data being returned - guard: unsafe { self.data.guard() }, - key, - _phantom: PhantomData, - }; - } - - let guard = unsafe { - 'outer: loop { - // safety: we have the thread key - locks[first_index].lock(); - for (i, lock) in locks.iter().enumerate() { - if i == first_index { - continue; - } - - // safety: we have the thread key - if !lock.try_lock() { - for lock in locks.iter().take(i) { - // safety: we already locked all of these - lock.unlock(); - } - - if first_index >= i { - // safety: this is already locked and can't be unlocked - // by the previous loop - locks[first_index].unlock(); - } - - first_index = i; - continue 'outer; - } - } - - // safety: we locked all the data - break self.data.guard(); - } - }; - - LockGuard { - guard, - key, - _phantom: PhantomData, - } - } - - pub fn try_lock<'a, 'key: 'a, Key: Keyable + 'key>( - &'a self, - key: Key, - ) -> Option<LockGuard<'a, 'key, L, Key>> { - let mut locks = Vec::new(); - self.data.get_ptrs(&mut locks); - - if locks.is_empty() { - return Some(LockGuard { - // safety: there's no data being returned - guard: unsafe { self.data.guard() }, - key, - _phantom: PhantomData, - }); - } - - let guard = unsafe { - for (i, lock) in locks.iter().enumerate() { - // safety: we have the thread key - if !lock.try_lock() { - for lock in locks.iter().take(i) { - // safety: we already locked all of these - lock.unlock(); - } - return None; - } - } - - // safety: we locked all the data - self.data.guard() - }; - - Some(LockGuard { - guard, - key, - _phantom: PhantomData, - }) - } - - pub fn unlock<'key, Key: Keyable + 'key>(guard: LockGuard<'_, 'key, L, Key>) -> Key { - drop(guard.guard); - guard.key - } -} @@ -113,8 +113,9 @@ pub mod collection; pub mod mutex; pub mod rwlock; +pub use collection::BoxedLockCollection as LockCollection; pub use key::{Keyable, ThreadKey}; -pub use lockable::{Lockable, OwnedLockable}; +pub use lockable::{Lockable, OwnedLockable, Sharable}; #[cfg(feature = "spin")] pub use mutex::SpinLock; diff --git a/src/lockable.rs b/src/lockable.rs index 9b3a4e4..23aeb4c 100644 --- a/src/lockable.rs +++ b/src/lockable.rs @@ -45,6 +45,12 @@ pub unsafe trait Lock: Send + Sync { /// /// It is undefined behavior to use this if the lock is not acquired unsafe fn unlock(&self); + + unsafe fn read(&self); + + unsafe fn try_read(&self) -> bool; + + unsafe fn unlock_read(&self); } pub unsafe trait Lockable { @@ -53,12 +59,21 @@ pub unsafe trait Lockable { where Self: 'g; + type ReadGuard<'g> + where + Self: 'g; + fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn Lock>); #[must_use] unsafe fn guard(&self) -> Self::Guard<'_>; + + #[must_use] + unsafe fn read_guard(&self) -> Self::ReadGuard<'_>; } +pub unsafe trait Sharable: Lockable {} + /// A type that may be locked and unlocked, and is known to be the only valid /// instance of the lock. /// @@ -80,6 +95,18 @@ unsafe impl<T: Send, R: RawMutex + Send + Sync> Lock for Mutex<T, R> { unsafe fn unlock(&self) { self.raw().unlock() } + + unsafe fn read(&self) { + self.raw().lock() + } + + unsafe fn try_read(&self) -> bool { + self.raw().try_lock() + } + + unsafe fn unlock_read(&self) { + self.raw().unlock() + } } unsafe impl<T: Send, R: RawRwLock + Send + Sync> Lock for RwLock<T, R> { @@ -94,10 +121,23 @@ unsafe impl<T: Send, R: RawRwLock + Send + Sync> Lock for RwLock<T, R> { unsafe fn unlock(&self) { self.raw().unlock_exclusive() } + + unsafe fn read(&self) { + self.raw().lock_shared() + } + + unsafe fn try_read(&self) -> bool { + self.raw().try_lock_shared() + } + + unsafe fn unlock_read(&self) { + self.raw().unlock_shared() + } } unsafe impl<T: Send, R: RawMutex + Send + Sync> Lockable for Mutex<T, R> { type Guard<'g> = MutexRef<'g, T, R> where Self: 'g; + type ReadGuard<'g> = MutexRef<'g, T, R> where Self: 'g; fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn Lock>) { ptrs.push(self); @@ -106,11 +146,17 @@ unsafe impl<T: Send, R: RawMutex + Send + Sync> Lockable for Mutex<T, R> { unsafe fn guard(&self) -> Self::Guard<'_> { MutexRef::new(self) } + + unsafe fn read_guard(&self) -> Self::ReadGuard<'_> { + MutexRef::new(self) + } } unsafe impl<T: Send, R: RawRwLock + Send + Sync> Lockable for RwLock<T, R> { type Guard<'g> = RwLockWriteRef<'g, T, R> where Self: 'g; + type ReadGuard<'g> = RwLockReadRef<'g, T, R> where Self: 'g; + fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn Lock>) { ptrs.push(self); } @@ -118,8 +164,14 @@ unsafe impl<T: Send, R: RawRwLock + Send + Sync> Lockable for RwLock<T, R> { unsafe fn guard(&self) -> Self::Guard<'_> { RwLockWriteRef::new(self) } + + unsafe fn read_guard(&self) -> Self::ReadGuard<'_> { + RwLockReadRef::new(self) + } } +unsafe impl<T: Send, R: RawRwLock + Send + Sync> Sharable for RwLock<T, R> {} + unsafe impl<T: Send, R: RawMutex + Send + Sync> OwnedLockable for Mutex<T, R> {} unsafe impl<T: Send, R: RawRwLock + Send + Sync> OwnedLockable for RwLock<T, R> {} @@ -127,6 +179,8 @@ unsafe impl<T: Send, R: RawRwLock + Send + Sync> OwnedLockable for RwLock<T, R> unsafe impl<'l, T: Send, R: RawRwLock + Send + Sync> Lockable for ReadLock<'l, T, R> { type Guard<'g> = RwLockReadRef<'g, T, R> where Self: 'g; + type ReadGuard<'g> = RwLockReadRef<'g, T, R> where Self: 'g; + fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn Lock>) { ptrs.push(self.as_ref()); } @@ -134,11 +188,17 @@ unsafe impl<'l, T: Send, R: RawRwLock + Send + Sync> Lockable for ReadLock<'l, T unsafe fn guard(&self) -> Self::Guard<'_> { RwLockReadRef::new(self.as_ref()) } + + unsafe fn read_guard(&self) -> Self::Guard<'_> { + RwLockReadRef::new(self.as_ref()) + } } unsafe impl<'l, T: Send, R: RawRwLock + Send + Sync> Lockable for WriteLock<'l, T, R> { type Guard<'g> = RwLockWriteRef<'g, T, R> where Self: 'g; + type ReadGuard<'g> = RwLockWriteRef<'g, T, R> where Self: 'g; + fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn Lock>) { ptrs.push(self.as_ref()); } @@ -146,11 +206,19 @@ unsafe impl<'l, T: Send, R: RawRwLock + Send + Sync> Lockable for WriteLock<'l, unsafe fn guard(&self) -> Self::Guard<'_> { RwLockWriteRef::new(self.as_ref()) } + + unsafe fn read_guard(&self) -> Self::Guard<'_> { + RwLockWriteRef::new(self.as_ref()) + } } +unsafe impl<'l, T: Send, R: RawRwLock + Send + Sync> Sharable for ReadLock<'l, T, R> {} + unsafe impl<T: Lockable> Lockable for &T { type Guard<'g> = T::Guard<'g> where Self: 'g; + type ReadGuard<'g> = T::ReadGuard<'g> where Self: 'g; + fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn Lock>) { (*self).get_ptrs(ptrs); } @@ -158,11 +226,17 @@ unsafe impl<T: Lockable> Lockable for &T { unsafe fn guard(&self) -> Self::Guard<'_> { (*self).guard() } + + unsafe fn read_guard(&self) -> Self::ReadGuard<'_> { + (*self).read_guard() + } } unsafe impl<T: Lockable> Lockable for &mut T { type Guard<'g> = T::Guard<'g> where Self: 'g; + type ReadGuard<'g> = T::ReadGuard<'g> where Self: 'g; + fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn Lock>) { (**self).get_ptrs(ptrs) } @@ -170,6 +244,10 @@ unsafe impl<T: Lockable> Lockable for &mut T { unsafe fn guard(&self) -> Self::Guard<'_> { (**self).guard() } + + unsafe fn read_guard(&self) -> Self::ReadGuard<'_> { + (**self).read_guard() + } } unsafe impl<T: OwnedLockable> OwnedLockable for &mut T {} @@ -177,6 +255,8 @@ unsafe impl<T: OwnedLockable> OwnedLockable for &mut T {} unsafe impl<A: Lockable> Lockable for (A,) { type Guard<'g> = (A::Guard<'g>,) where Self: 'g; + type ReadGuard<'g> = (A::ReadGuard<'g>,) where Self: 'g; + fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn Lock>) { self.0.get_ptrs(ptrs); } @@ -184,11 +264,17 @@ unsafe impl<A: Lockable> Lockable for (A,) { unsafe fn guard(&self) -> Self::Guard<'_> { (self.0.guard(),) } + + unsafe fn read_guard(&self) -> Self::ReadGuard<'_> { + (self.0.read_guard(),) + } } unsafe impl<A: Lockable, B: Lockable> Lockable for (A, B) { type Guard<'g> = (A::Guard<'g>, B::Guard<'g>) where Self: 'g; + type ReadGuard<'g> = (A::ReadGuard<'g>, B::ReadGuard<'g>) where Self: 'g; + fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn Lock>) { self.0.get_ptrs(ptrs); self.1.get_ptrs(ptrs); @@ -197,11 +283,17 @@ unsafe impl<A: Lockable, B: Lockable> Lockable for (A, B) { unsafe fn guard(&self) -> Self::Guard<'_> { (self.0.guard(), self.1.guard()) } + + unsafe fn read_guard(&self) -> Self::ReadGuard<'_> { + (self.0.read_guard(), self.1.read_guard()) + } } unsafe impl<A: Lockable, B: Lockable, C: Lockable> Lockable for (A, B, C) { type Guard<'g> = (A::Guard<'g>, B::Guard<'g>, C::Guard<'g>) where Self: 'g; + type ReadGuard<'g> = (A::ReadGuard<'g>, B::ReadGuard<'g>, C::ReadGuard<'g>) where Self: 'g; + fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn Lock>) { self.0.get_ptrs(ptrs); self.1.get_ptrs(ptrs); @@ -211,11 +303,26 @@ unsafe impl<A: Lockable, B: Lockable, C: Lockable> Lockable for (A, B, C) { unsafe fn guard(&self) -> Self::Guard<'_> { (self.0.guard(), self.1.guard(), self.2.guard()) } + + unsafe fn read_guard(&self) -> Self::ReadGuard<'_> { + ( + self.0.read_guard(), + self.1.read_guard(), + self.2.read_guard(), + ) + } } unsafe impl<A: Lockable, B: Lockable, C: Lockable, D: Lockable> Lockable for (A, B, C, D) { type Guard<'g> = (A::Guard<'g>, B::Guard<'g>, C::Guard<'g>, D::Guard<'g>) where Self: 'g; + type ReadGuard<'g> = ( + A::ReadGuard<'g>, + B::ReadGuard<'g>, + C::ReadGuard<'g>, + D::ReadGuard<'g>, + ) where Self: 'g; + fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn Lock>) { self.0.get_ptrs(ptrs); self.1.get_ptrs(ptrs); @@ -231,6 +338,15 @@ unsafe impl<A: Lockable, B: Lockable, C: Lockable, D: Lockable> Lockable for (A, self.3.guard(), ) } + + unsafe fn read_guard(&self) -> Self::ReadGuard<'_> { + ( + self.0.read_guard(), + self.1.read_guard(), + self.2.read_guard(), + self.3.read_guard(), + ) + } } unsafe impl<A: Lockable, B: Lockable, C: Lockable, D: Lockable, E: Lockable> Lockable @@ -244,6 +360,14 @@ unsafe impl<A: Lockable, B: Lockable, C: Lockable, D: Lockable, E: Lockable> Loc E::Guard<'g>, ) where Self: 'g; + type ReadGuard<'g> = ( + A::ReadGuard<'g>, + B::ReadGuard<'g>, + C::ReadGuard<'g>, + D::ReadGuard<'g>, + E::ReadGuard<'g>, + ) where Self: 'g; + fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn Lock>) { self.0.get_ptrs(ptrs); self.1.get_ptrs(ptrs); @@ -261,6 +385,16 @@ unsafe impl<A: Lockable, B: Lockable, C: Lockable, D: Lockable, E: Lockable> Loc self.4.guard(), ) } + + unsafe fn read_guard(&self) -> Self::ReadGuard<'_> { + ( + self.0.read_guard(), + self.1.read_guard(), + self.2.read_guard(), + self.3.read_guard(), + self.4.read_guard(), + ) + } } unsafe impl<A: Lockable, B: Lockable, C: Lockable, D: Lockable, E: Lockable, F: Lockable> Lockable @@ -275,6 +409,15 @@ unsafe impl<A: Lockable, B: Lockable, C: Lockable, D: Lockable, E: Lockable, F: F::Guard<'g>, ) where Self: 'g; + type ReadGuard<'g> = ( + A::ReadGuard<'g>, + B::ReadGuard<'g>, + C::ReadGuard<'g>, + D::ReadGuard<'g>, + E::ReadGuard<'g>, + F::ReadGuard<'g>, + ) where Self: 'g; + fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn Lock>) { self.0.get_ptrs(ptrs); self.1.get_ptrs(ptrs); @@ -294,6 +437,17 @@ unsafe impl<A: Lockable, B: Lockable, C: Lockable, D: Lockable, E: Lockable, F: self.5.guard(), ) } + + unsafe fn read_guard(&self) -> Self::ReadGuard<'_> { + ( + self.0.read_guard(), + self.1.read_guard(), + self.2.read_guard(), + self.3.read_guard(), + self.4.read_guard(), + self.5.read_guard(), + ) + } } unsafe impl<A: Lockable, B: Lockable, C: Lockable, D: Lockable, E: Lockable, F: Lockable, G: Lockable> @@ -309,6 +463,16 @@ unsafe impl<A: Lockable, B: Lockable, C: Lockable, D: Lockable, E: Lockable, F: G::Guard<'g>, ) where Self: 'g; + type ReadGuard<'g> = ( + A::ReadGuard<'g>, + B::ReadGuard<'g>, + C::ReadGuard<'g>, + D::ReadGuard<'g>, + E::ReadGuard<'g>, + F::ReadGuard<'g>, + G::ReadGuard<'g>, + ) where Self: 'g; + fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn Lock>) { self.0.get_ptrs(ptrs); self.1.get_ptrs(ptrs); @@ -330,6 +494,40 @@ unsafe impl<A: Lockable, B: Lockable, C: Lockable, D: Lockable, E: Lockable, F: self.6.guard(), ) } + + unsafe fn read_guard(&self) -> Self::ReadGuard<'_> { + ( + self.0.read_guard(), + self.1.read_guard(), + self.2.read_guard(), + self.3.read_guard(), + self.4.read_guard(), + self.5.read_guard(), + self.6.read_guard(), + ) + } +} + +unsafe impl<A: Sharable> Sharable for (A,) {} +unsafe impl<A: Sharable, B: Sharable> Sharable for (A, B) {} + +unsafe impl<A: Sharable, B: Sharable, C: Sharable> Sharable for (A, B, C) {} + +unsafe impl<A: Sharable, B: Sharable, C: Sharable, D: Sharable> Sharable for (A, B, C, D) {} + +unsafe impl<A: Sharable, B: Sharable, C: Sharable, D: Sharable, E: Sharable> Sharable + for (A, B, C, D, E) +{ +} + +unsafe impl<A: Sharable, B: Sharable, C: Sharable, D: Sharable, E: Sharable, F: Sharable> Sharable + for (A, B, C, D, E, F) +{ +} + +unsafe impl<A: Sharable, B: Sharable, C: Sharable, D: Sharable, E: Sharable, F: Sharable, G: Sharable> + Sharable for (A, B, C, D, E, F, G) +{ } unsafe impl<A: OwnedLockable> OwnedLockable for (A,) {} @@ -373,6 +571,8 @@ unsafe impl< unsafe impl<T: Lockable, const N: usize> Lockable for [T; N] { type Guard<'g> = [T::Guard<'g>; N] where Self: 'g; + type ReadGuard<'g> = [T::ReadGuard<'g>; N] where Self: 'g; + fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn Lock>) { for lock in self { lock.get_ptrs(ptrs); @@ -387,11 +587,22 @@ unsafe impl<T: Lockable, const N: usize> Lockable for [T; N] { guards.map(|g| g.assume_init()) } + + unsafe fn read_guard<'g>(&'g self) -> Self::ReadGuard<'g> { + let mut guards = MaybeUninit::<[MaybeUninit<T::ReadGuard<'g>>; N]>::uninit().assume_init(); + for i in 0..N { + guards[i].write(self[i].read_guard()); + } + + guards.map(|g| g.assume_init()) + } } unsafe impl<T: Lockable> Lockable for Box<[T]> { type Guard<'g> = Box<[T::Guard<'g>]> where Self: 'g; + type ReadGuard<'g> = Box<[T::ReadGuard<'g>]> where Self: 'g; + fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn Lock>) { for lock in self.iter() { lock.get_ptrs(ptrs); @@ -406,11 +617,22 @@ unsafe impl<T: Lockable> Lockable for Box<[T]> { guards.into_boxed_slice() } + + unsafe fn read_guard(&self) -> Self::ReadGuard<'_> { + let mut guards = Vec::new(); + for lock in self.iter() { + guards.push(lock.read_guard()); + } + + guards.into_boxed_slice() + } } unsafe impl<T: Lockable> Lockable for Vec<T> { type Guard<'g> = Vec<T::Guard<'g>> where Self: 'g; + type ReadGuard<'g> = Box<[T::ReadGuard<'g>]> where Self: 'g; + fn get_ptrs<'a>(&'a self, ptrs: &mut Vec<&'a dyn Lock>) { for lock in self { lock.get_ptrs(ptrs); @@ -425,8 +647,21 @@ unsafe impl<T: Lockable> Lockable for Vec<T> { guards } + + unsafe fn read_guard(&self) -> Self::ReadGuard<'_> { + let mut guards = Vec::new(); + for lock in self { + guards.push(lock.read_guard()); + } + + guards.into_boxed_slice() + } } +unsafe impl<T: Sharable, const N: usize> Sharable for [T; N] {} +unsafe impl<T: Sharable> Sharable for Box<[T]> {} +unsafe impl<T: Sharable> Sharable for Vec<T> {} + unsafe impl<T: OwnedLockable, const N: usize> OwnedLockable for [T; N] {} unsafe impl<T: OwnedLockable> OwnedLockable for Box<[T]> {} unsafe impl<T: OwnedLockable> OwnedLockable for Vec<T> {} |
