diff options
Diffstat (limited to 'src/collection')
| -rw-r--r-- | src/collection/boxed_collection.rs | 60 | ||||
| -rw-r--r-- | src/collection/owned_collection.rs | 68 | ||||
| -rw-r--r-- | src/collection/ref_collection.rs (renamed from src/collection/collection.rs) | 1 |
3 files changed, 129 insertions, 0 deletions
diff --git a/src/collection/boxed_collection.rs b/src/collection/boxed_collection.rs new file mode 100644 index 0000000..bcb941b --- /dev/null +++ b/src/collection/boxed_collection.rs @@ -0,0 +1,60 @@ +use std::ops::{Deref, DerefMut}; + +use crate::{Lockable, OwnedLockable}; + +use super::{BoxedLockCollection, RefLockCollection}; + +impl<'a, L> Deref for BoxedLockCollection<'a, L> { + type Target = RefLockCollection<'a, L>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<'a, L> DerefMut for BoxedLockCollection<'a, L> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl<'a, L> 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()) }; + drop(boxed); + } +} + +impl<'a, L: OwnedLockable<'a> + 'a> BoxedLockCollection<'a, L> { + #[must_use] + pub fn new(data: L) -> Self { + let boxed = Box::leak(Box::new(data)); + Self(RefLockCollection::new(boxed)) + } +} + +impl<'a, L: OwnedLockable<'a> + 'a> BoxedLockCollection<'a, &'a L> { + #[must_use] + pub fn new_ref(data: &'a L) -> Self { + let boxed = Box::leak(Box::new(data)); + + // this is a reference to an OwnedLockable, which can't possibly + // contain inner duplicates + Self(unsafe { RefLockCollection::new_unchecked(boxed) }) + } +} + +impl<'a, L: Lockable<'a> + 'a> BoxedLockCollection<'a, L> { + #[must_use] + pub unsafe fn new_unchecked(data: L) -> Self { + let boxed = Box::leak(Box::new(data)); + Self(RefLockCollection::new_unchecked(boxed)) + } + + #[must_use] + pub fn try_new(data: L) -> Option<Self> { + let boxed = Box::leak(Box::new(data)); + RefLockCollection::try_new(boxed).map(Self) + } +} diff --git a/src/collection/owned_collection.rs b/src/collection/owned_collection.rs new file mode 100644 index 0000000..dbc9a45 --- /dev/null +++ b/src/collection/owned_collection.rs @@ -0,0 +1,68 @@ +use std::marker::PhantomData; + +use crate::{lockable::Lock, Keyable, Lockable, OwnedLockable}; + +use super::{LockGuard, OwnedLockCollection}; + +fn get_locks<'a, L: Lockable<'a> + 'a>(data: &'a L) -> Vec<&'a dyn Lock> { + let mut locks = Vec::new(); + data.get_ptrs(&mut locks); + locks +} + +impl<'a, L: OwnedLockable<'a>> OwnedLockCollection<L> { + #[must_use] + pub const fn new(data: L) -> Self { + Self { data } + } + + pub fn lock<'s: 'a, 'key, Key: Keyable + 'key>( + &'s 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<'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/collection.rs b/src/collection/ref_collection.rs index a8d25a5..3e4d5f8 100644 --- a/src/collection/collection.rs +++ b/src/collection/ref_collection.rs @@ -4,6 +4,7 @@ use crate::{key::Keyable, lockable::Lock, Lockable, OwnedLockable}; use super::{LockGuard, RefLockCollection}; +#[must_use] fn get_locks<'a, L: Lockable<'a> + 'a>(data: &'a L) -> Vec<&'a dyn Lock> { let mut locks = Vec::new(); data.get_ptrs(&mut locks); |
