summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xsrc/collection/owned.rs27
-rw-r--r--src/iterator.rs29
-rw-r--r--src/iterator/consumed_guard.rs58
-rw-r--r--src/iterator/context.rs52
-rw-r--r--src/iterator/iterator.rs81
-rw-r--r--src/iterator/tuple.rs202
-rwxr-xr-xsrc/lockable.rs7
7 files changed, 331 insertions, 125 deletions
diff --git a/src/collection/owned.rs b/src/collection/owned.rs
index a7ab1b6..07a5402 100755
--- a/src/collection/owned.rs
+++ b/src/collection/owned.rs
@@ -1,4 +1,4 @@
-use crate::iterator::LockingIterator;
+use crate::iterator::LockContext;
use crate::lockable::{
Lockable, LockableGetMut, LockableIntoInner, OwnedLockable, RawLock, Sharable,
};
@@ -559,6 +559,10 @@ impl<L: Sharable> OwnedLockCollection<L> {
}
impl<L> OwnedLockCollection<L> {
+ pub const fn context(&self) -> LockContext<'_, L> {
+ LockContext::new(&self.child)
+ }
+
/// Gets the underlying collection, consuming this collection.
///
/// # Examples
@@ -641,27 +645,6 @@ impl<L: LockableIntoInner> OwnedLockCollection<L> {
}
}
-impl<L: OwnedLockable> OwnedLockCollection<L>
-where
- for<'a> &'a L: IntoIterator,
-{
- pub fn locking_iter(
- &self,
- key: ThreadKey,
- ) -> LockingIterator<<&L as IntoIterator>::IntoIter, ThreadKey> {
- LockingIterator::new(key, (&self.child).into_iter())
- }
-
- pub fn scoped_locking_iter<Key: Keyable, R>(
- &self,
- key: Key,
- f: impl FnOnce(&mut LockingIterator<<&L as IntoIterator>::IntoIter, Key>) -> R,
- ) -> R {
- let mut iterator = LockingIterator::new(key, (&self.child).into_iter());
- f(&mut iterator)
- }
-}
-
#[cfg(test)]
mod tests {
use super::*;
diff --git a/src/iterator.rs b/src/iterator.rs
index 30b01e0..79a2cc5 100644
--- a/src/iterator.rs
+++ b/src/iterator.rs
@@ -1,18 +1,29 @@
-mod consumed_guard;
+use std::marker::PhantomData;
+
+use crate::ThreadKey;
+
+mod context;
mod guard;
mod iterator;
+mod tuple;
-pub struct LockingIterator<L, Key> {
- key: Key,
- lockable: L,
+pub struct LockingIterator<'context, I> {
+ key: &'context ThreadKey,
+ iterator: I,
}
-pub struct IteratorGuard<'a, Guard, Key> {
- _key: &'a Key,
- guard: Guard,
+pub struct LockingTuple<'context, L, C> {
+ _lockable: PhantomData<L>,
+ key: &'context ThreadKey,
+ tuple: &'context C,
}
-pub struct ConsumedIteratorGuard<Guard, Key> {
- key: Key,
+pub struct LockContext<'l, L> {
+ key: Option<ThreadKey>,
+ lockable: &'l L,
+}
+
+pub struct IteratorGuard<'a, Guard, Key> {
+ _key: &'a Key,
guard: Guard,
}
diff --git a/src/iterator/consumed_guard.rs b/src/iterator/consumed_guard.rs
deleted file mode 100644
index 5331289..0000000
--- a/src/iterator/consumed_guard.rs
+++ /dev/null
@@ -1,58 +0,0 @@
-use std::fmt::{Debug, Display};
-use std::hash::Hash;
-use std::ops::{Deref, DerefMut};
-
-use crate::iterator::ConsumedIteratorGuard;
-
-#[mutants::skip] // hashing involves RNG and is hard to test
-#[cfg(not(tarpaulin_include))]
-impl<Guard: Hash, Key> Hash for ConsumedIteratorGuard<Guard, Key> {
- fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
- self.guard.hash(state)
- }
-}
-
-// No implementations of Eq, PartialEq, PartialOrd, or Ord
-// You can't implement both PartialEq<Self> and PartialEq<T>
-// It's easier to just implement neither and ask users to dereference
-// This is less of a problem when using the scoped lock API
-
-#[mutants::skip]
-#[cfg(not(tarpaulin_include))]
-impl<Guard: Debug, Key> Debug for ConsumedIteratorGuard<Guard, Key> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- Debug::fmt(&**self, f)
- }
-}
-
-impl<Guard: Display, Key> Display for ConsumedIteratorGuard<Guard, Key> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- Display::fmt(&**self, f)
- }
-}
-
-impl<Guard, Key> Deref for ConsumedIteratorGuard<Guard, Key> {
- type Target = Guard;
-
- fn deref(&self) -> &Self::Target {
- &self.guard
- }
-}
-
-impl<Guard, Key> DerefMut for ConsumedIteratorGuard<Guard, Key> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.guard
- }
-}
-
-impl<Guard, Key> AsRef<Guard> for ConsumedIteratorGuard<Guard, Key> {
- fn as_ref(&self) -> &Guard {
- &self.guard
- }
-}
-
-impl<Guard, Key> AsMut<Guard> for ConsumedIteratorGuard<Guard, Key> {
- fn as_mut(&mut self) -> &mut Guard {
- &mut self.guard
- }
-}
diff --git a/src/iterator/context.rs b/src/iterator/context.rs
new file mode 100644
index 0000000..a5c9123
--- /dev/null
+++ b/src/iterator/context.rs
@@ -0,0 +1,52 @@
+use std::marker::PhantomData;
+
+use crate::{
+ iterator::{LockContext, LockingIterator, LockingTuple},
+ lockable::Lockable,
+ ThreadKey,
+};
+
+impl<'l, L> LockContext<'l, L> {
+ pub(crate) const fn new(lockable: &'l L) -> Self {
+ Self {
+ key: None,
+ lockable,
+ }
+ }
+}
+
+impl<L: Lockable> LockContext<'_, L> {
+ pub fn tuple(&mut self, key: ThreadKey) -> LockingTuple<'_, L, L> {
+ unsafe {
+ self.key = Some(key);
+
+ LockingTuple {
+ _lockable: PhantomData,
+ // safety: we just inserted a key
+ key: self.key.as_ref().unwrap_unchecked(),
+ tuple: self.lockable,
+ }
+ }
+ }
+}
+
+impl<'l, L> LockContext<'l, L>
+where
+ &'l L: IntoIterator,
+{
+ #[expect(clippy::iter_not_returning_iterator)]
+ pub fn iter(
+ &mut self,
+ key: ThreadKey,
+ ) -> LockingIterator<'_, <&'l L as IntoIterator>::IntoIter> {
+ unsafe {
+ self.key = Some(key);
+
+ LockingIterator {
+ // safety: we just inserted a key
+ key: self.key.as_ref().unwrap_unchecked(),
+ iterator: self.lockable.into_iter(),
+ }
+ }
+ }
+}
diff --git a/src/iterator/iterator.rs b/src/iterator/iterator.rs
index 1e389a4..316a276 100644
--- a/src/iterator/iterator.rs
+++ b/src/iterator/iterator.rs
@@ -1,36 +1,32 @@
use std::iter::{Enumerate, Fuse, Skip, Take};
-use super::{ConsumedIteratorGuard, IteratorGuard, LockingIterator};
+use super::{IteratorGuard, LockingIterator};
use crate::{
lockable::{Lockable, RawLock, Sharable},
- Keyable,
+ ThreadKey,
};
-impl<L, Key> LockingIterator<L, Key> {
- pub(crate) const fn new(key: Key, lockable: L) -> Self {
- Self { key, lockable }
- }
-
- fn with_iterator<M>(self, f: impl FnOnce(L) -> M) -> LockingIterator<M, Key> {
+impl<'l, I> LockingIterator<'l, I> {
+ fn with_iterator<M>(self, f: impl FnOnce(I) -> M) -> LockingIterator<'l, M> {
LockingIterator {
key: self.key,
- lockable: f(self.lockable),
+ iterator: f(self.iterator),
}
}
}
-impl<'a, I: Iterator<Item = &'a L>, L: 'a + Lockable + RawLock, Key: Keyable>
- LockingIterator<I, Key>
-{
- pub fn lock_next(&'a mut self) -> Option<IteratorGuard<'a, <L as Lockable>::Guard<'a>, Key>> {
- if let Some(lock) = self.lockable.next() {
+impl<'c, L: 'c + Iterator<Item = &'c I>, I: 'c + RawLock + Lockable> LockingIterator<'c, L> {
+ pub fn lock_next(
+ &mut self,
+ ) -> Option<IteratorGuard<'c, <I as Lockable>::Guard<'c>, ThreadKey>> {
+ if let Some(lock) = self.iterator.next() {
unsafe {
lock.raw_write();
let guard = lock.guard();
Some(IteratorGuard {
- _key: &self.key,
+ _key: self.key,
guard,
})
}
@@ -39,32 +35,30 @@ impl<'a, I: Iterator<Item = &'a L>, L: 'a + Lockable + RawLock, Key: Keyable>
}
}
- pub fn lock_last(self) -> Option<ConsumedIteratorGuard<<L as Lockable>::Guard<'a>, Key>> {
- self.lockable.last().map(|lock| unsafe {
+ pub fn lock_last(self) -> Option<IteratorGuard<'c, <I as Lockable>::Guard<'c>, ThreadKey>> {
+ self.iterator.last().map(|lock| unsafe {
lock.raw_write();
let guard = lock.guard();
- ConsumedIteratorGuard {
- key: self.key,
+ IteratorGuard {
+ _key: self.key,
guard,
}
})
}
}
-impl<'a, I: Iterator<Item = &'a L>, L: 'a + Sharable + RawLock, Key: Keyable>
- LockingIterator<I, Key>
-{
+impl<'c, L: 'c + Iterator<Item = &'c I>, I: 'c + RawLock + Sharable> LockingIterator<'c, L> {
pub fn read_next(
- &'a mut self,
- ) -> Option<IteratorGuard<'a, <L as Sharable>::ReadGuard<'a>, Key>> {
- if let Some(lock) = self.lockable.next() {
+ &mut self,
+ ) -> Option<IteratorGuard<'c, <I as Sharable>::ReadGuard<'c>, ThreadKey>> {
+ if let Some(lock) = self.iterator.next() {
unsafe {
lock.raw_read();
let guard = lock.read_guard();
Some(IteratorGuard {
- _key: &self.key,
+ _key: self.key,
guard,
})
}
@@ -73,37 +67,52 @@ impl<'a, I: Iterator<Item = &'a L>, L: 'a + Sharable + RawLock, Key: Keyable>
}
}
- pub fn read_last(self) -> Option<ConsumedIteratorGuard<<L as Sharable>::ReadGuard<'a>, Key>> {
- self.lockable.last().map(|lock| unsafe {
+ pub fn read_last(self) -> Option<IteratorGuard<'c, <I as Sharable>::ReadGuard<'c>, ThreadKey>> {
+ self.iterator.last().map(|lock| unsafe {
lock.raw_read();
let guard = lock.read_guard();
- ConsumedIteratorGuard {
- key: self.key,
+ IteratorGuard {
+ _key: self.key,
guard,
}
})
}
}
-impl<L: Iterator, Key> LockingIterator<L, Key> {
+impl<'l, L: Iterator> LockingIterator<'l, L> {
+ pub fn skip_next(&mut self) -> Option<L::Item> {
+ self.iterator.next()
+ }
+
+ pub fn skip_mut(&mut self, n: usize) {
+ for _ in 0..n {
+ self.iterator.next();
+ }
+ }
+
+ #[must_use]
pub fn size_hint(&self) -> (usize, Option<usize>) {
- self.lockable.size_hint()
+ self.iterator.size_hint()
}
- pub fn enumerate(self) -> LockingIterator<Enumerate<L>, Key> {
+ #[must_use]
+ pub fn enumerate(self) -> LockingIterator<'l, Enumerate<L>> {
self.with_iterator(Iterator::enumerate)
}
- pub fn skip(self, n: usize) -> LockingIterator<Skip<L>, Key> {
+ #[must_use]
+ pub fn skip(self, n: usize) -> LockingIterator<'l, Skip<L>> {
self.with_iterator(|i| i.skip(n))
}
- pub fn take(self, n: usize) -> LockingIterator<Take<L>, Key> {
+ #[must_use]
+ pub fn take(self, n: usize) -> LockingIterator<'l, Take<L>> {
self.with_iterator(|i| i.take(n))
}
- pub fn fuse(self) -> LockingIterator<Fuse<L>, Key> {
+ #[must_use]
+ pub fn fuse(self) -> LockingIterator<'l, Fuse<L>> {
self.with_iterator(Iterator::fuse)
}
}
diff --git a/src/iterator/tuple.rs b/src/iterator/tuple.rs
new file mode 100644
index 0000000..855cdc7
--- /dev/null
+++ b/src/iterator/tuple.rs
@@ -0,0 +1,202 @@
+use std::marker::PhantomData;
+
+use crate::{
+ iterator::{IteratorGuard, LockingTuple},
+ lockable::{Lockable, RawLock},
+ ThreadKey,
+};
+
+impl<'c, A, B> LockingTuple<'c, A, B> {
+ const fn transmute<C>(self) -> LockingTuple<'c, C, B> {
+ LockingTuple {
+ _lockable: PhantomData,
+ key: self.key,
+ tuple: self.tuple,
+ }
+ }
+}
+
+macro_rules! lock_impl {
+ ($self: expr, $field: tt) => {
+ unsafe {
+ $self.tuple.$field.raw_write();
+ (
+ IteratorGuard {
+ _key: &$self.key,
+ guard: $self.tuple.$field.guard(),
+ },
+ $self.transmute(),
+ )
+ }
+ };
+}
+
+macro_rules! recurse_impl {
+ ($self: expr, $field: tt) => {
+ LockingTuple {
+ _lockable: PhantomData,
+ key: $self.key,
+ tuple: &$self.tuple.$field,
+ }
+ };
+}
+
+type LockReturn<'a, 'context, Guarded, L, C> = (
+ IteratorGuard<'a, <Guarded as Lockable>::Guard<'a>, ThreadKey>,
+ LockingTuple<'context, L, C>,
+);
+
+impl<'context, A: RawLock + Lockable> LockingTuple<'context, (A,), (A,)> {
+ #[must_use]
+ pub fn lock_0<'a>(self) -> LockReturn<'a, 'context, A, ((),), (A,)>
+ where
+ 'context: 'a,
+ {
+ lock_impl!(self, 0)
+ }
+}
+
+impl<'context, A> LockingTuple<'context, (A,), (A,)> {
+ #[must_use]
+ pub const fn recurse_0(self) -> LockingTuple<'context, A, A> {
+ recurse_impl!(self, 0)
+ }
+}
+
+impl<'context, A: RawLock + Lockable, B, B0> LockingTuple<'context, (A, B), (A, B0)> {
+ #[must_use]
+ pub fn lock_0<'a>(self) -> LockReturn<'a, 'context, A, ((), B), (A, B0)>
+ where
+ 'context: 'a,
+ {
+ lock_impl!(self, 0)
+ }
+}
+
+impl<'context, A, B, B0> LockingTuple<'context, (A, B), (A, B0)> {
+ #[must_use]
+ pub const fn recurse_0(self) -> LockingTuple<'context, A, A> {
+ recurse_impl!(self, 0)
+ }
+}
+
+impl<'context, A: Lockable + RawLock, B> LockingTuple<'context, (A, B), (A, B)> {
+ #[must_use]
+ pub fn lock_and_recurse<'a>(
+ self,
+ ) -> (
+ IteratorGuard<'a, <A as Lockable>::Guard<'a>, ThreadKey>,
+ LockingTuple<'context, B, B>,
+ )
+ where
+ 'context: 'a,
+ {
+ unsafe {
+ self.tuple.0.raw_write();
+ (
+ IteratorGuard {
+ _key: self.key,
+ guard: self.tuple.0.guard(),
+ },
+ LockingTuple {
+ _lockable: PhantomData,
+ key: self.key,
+ tuple: &self.tuple.1,
+ },
+ )
+ }
+ }
+}
+
+impl<'context, A, A0, B: RawLock + Lockable> LockingTuple<'context, (A, B), (A0, B)> {
+ #[must_use]
+ pub fn lock_1<'a>(self) -> LockReturn<'a, 'context, B, ((), ()), (A0, B)>
+ where
+ 'context: 'a,
+ {
+ lock_impl!(self, 1)
+ }
+}
+
+impl<'context, A, A0, B> LockingTuple<'context, (A, B), (A0, B)> {
+ #[must_use]
+ pub const fn recurse_1(self) -> LockingTuple<'context, B, B> {
+ recurse_impl!(self, 1)
+ }
+}
+
+impl<'context, A: RawLock + Lockable, B, B0, C, C0> LockingTuple<'context, (A, B, C), (A, B0, C0)> {
+ #[must_use]
+ pub fn lock_0<'a>(self) -> LockReturn<'a, 'context, A, ((), B, C), (A, B0, C0)>
+ where
+ 'context: 'a,
+ {
+ lock_impl!(self, 0)
+ }
+}
+
+impl<'context, A, B, B0, C, C0> LockingTuple<'context, (A, B, C), (A, B0, C0)> {
+ #[must_use]
+ pub const fn recurse_0(self) -> LockingTuple<'context, A, A> {
+ recurse_impl!(self, 0)
+ }
+}
+
+impl<'context, A, A0, B: RawLock + Lockable, C, C0> LockingTuple<'context, (A, B, C), (A0, B, C0)> {
+ #[must_use]
+ pub fn lock_1<'a>(self) -> LockReturn<'a, 'context, B, ((), (), C), (A0, B, C0)>
+ where
+ 'context: 'a,
+ {
+ lock_impl!(self, 1)
+ }
+}
+
+impl<'context, A, A0, B, C, C0> LockingTuple<'context, (A, B, C), (A0, B, C0)> {
+ #[must_use]
+ pub const fn recurse_1(self) -> LockingTuple<'context, B, B> {
+ recurse_impl!(self, 1)
+ }
+}
+
+impl<'context, A, A0, B, B0, C: RawLock + Lockable> LockingTuple<'context, (A, B, C), (A0, B0, C)> {
+ #[must_use]
+ pub fn lock_2<'a>(self) -> LockReturn<'a, 'context, C, ((), (), ()), (A0, B0, C)>
+ where
+ 'context: 'a,
+ {
+ lock_impl!(self, 2)
+ }
+}
+
+impl<'context, A, A0, B, B0, C> LockingTuple<'context, (A, B, C), (A0, B0, C)> {
+ #[must_use]
+ pub const fn recurse_2(self) -> LockingTuple<'context, C, C> {
+ recurse_impl!(self, 2)
+ }
+}
+
+impl<'context, A, B, B0, C, C0, D, D0> LockingTuple<'context, (A, B, C, D), (A, B0, C0, D0)> {
+ #[must_use]
+ pub const fn recurse_0(self) -> LockingTuple<'context, A, A> {
+ recurse_impl!(self, 0)
+ }
+}
+impl<'context, A, A0, B, C, C0, D, D0> LockingTuple<'context, (A, B, C, D), (A0, B, C0, D0)> {
+ #[must_use]
+ pub const fn recurse_1(self) -> LockingTuple<'context, B, B> {
+ recurse_impl!(self, 1)
+ }
+}
+impl<'context, A, A0, B, B0, C, D, D0> LockingTuple<'context, (A, B, C, D), (A0, B0, C, D0)> {
+ #[must_use]
+ pub const fn recurse_2(self) -> LockingTuple<'context, C, C> {
+ recurse_impl!(self, 2)
+ }
+}
+impl<'context, A, A0, B, B0, C, C0, D> LockingTuple<'context, (A, B, C, D), (A0, B0, C0, D)> {
+ #[must_use]
+ pub const fn recurse_3(self) -> LockingTuple<'context, D, D> {
+ recurse_impl!(self, 3)
+ }
+}
diff --git a/src/lockable.rs b/src/lockable.rs
index 56cbb52..badbe8e 100755
--- a/src/lockable.rs
+++ b/src/lockable.rs
@@ -401,6 +401,13 @@ tuple_impls!(A B C D, 0 1 2 3);
tuple_impls!(A B C D E, 0 1 2 3 4);
tuple_impls!(A B C D E F, 0 1 2 3 4 5);
tuple_impls!(A B C D E F G, 0 1 2 3 4 5 6);
+tuple_impls!(A B C D E F G H, 0 1 2 3 4 5 6 7);
+tuple_impls!(A B C D E F G H I, 0 1 2 3 4 5 6 7 8);
+tuple_impls!(A B C D E F G H I J, 0 1 2 3 4 5 6 7 8 9);
+tuple_impls!(A B C D E F G H I J K, 0 1 2 3 4 5 6 7 8 9 10);
+tuple_impls!(A B C D E F G H I J K L, 0 1 2 3 4 5 6 7 8 9 10 11);
+tuple_impls!(A B C D E F G H I J K L M, 0 1 2 3 4 5 6 7 8 9 10 11 12);
+tuple_impls!(A B C D E F G H I J K L M N, 0 1 2 3 4 5 6 7 8 9 10 11 12 13);
unsafe impl<T: Lockable, const N: usize> Lockable for [T; N] {
type Guard<'g>