From 0a6bd8f2c0a7c79d17f5dc9e64af0b4c6c745166 Mon Sep 17 00:00:00 2001 From: Mica White Date: Wed, 26 Aug 2026 21:03:22 -0400 Subject: Comments --- src/context.rs | 12 ++++++++++++ src/context/context.rs | 6 +++++- src/context/iterator.rs | 7 +++++++ src/context/tuple.rs | 8 ++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/context.rs b/src/context.rs index 2f9ca64..1707022 100644 --- a/src/context.rs +++ b/src/context.rs @@ -66,7 +66,16 @@ pub mod tuple; /// ``` /// /// [`OwnedLockCollection::context`]: crate::collection::OwnedLockCollection::context +// This is only available from OwnedLockCollection because it ensures the lock +// order is the same as the one provided by this function. Tuples may have +// their elements re-ordered by the compiler. +// +// This struct is just a fancy place to hold the ThreadKey while it's being +// borrowed by multiple other guards. pub struct LockContext<'l, L> { + // Unfortunately there is no better way to get this into the context than to + // use an option, initialize to `None` and insert it later. If we returned a + // new type, that would move the thread key while it's being borrowed. key: Option, lockable: &'l L, } @@ -165,6 +174,9 @@ pub struct LockingTuple<'context, L, C, Outer = ()> { /// [`lock`]: `crate::mutex::Mutex::lock` /// [`try_lock`]: `crate::Mutex::try_lock` pub struct ContextGuard<'a, Guard, Key> { + // The idea behind having this be a shared reference is that it allows + // guards to exist at once. And while these borrows exist, the thread key will + // not be able to be reused somewhere else. _key: &'a Key, guard: Guard, } diff --git a/src/context/context.rs b/src/context/context.rs index adc684f..80a1881 100644 --- a/src/context/context.rs +++ b/src/context/context.rs @@ -7,7 +7,9 @@ use crate::{ }; impl<'l, L> LockContext<'l, L> { - pub(crate) const fn new(lockable: &'l L) -> Self + /// Safety: Don't lock the locks in a different order than what the + /// LockContext uses + pub(crate) const unsafe fn new(lockable: &'l L) -> Self where L: OwnedLockable, { @@ -56,6 +58,8 @@ impl<'l, L> LockContext<'l, L> { /// ``` /// /// [`ContextGuard`]: `crate::context::ContextGuard` + // The mutable reference ensures that all of the guards, which have a shared + // borrow to the context, must be dropped first pub fn unlock(&mut self) -> Option { self.key.take() } diff --git a/src/context/iterator.rs b/src/context/iterator.rs index cc3bd7c..1eacaea 100644 --- a/src/context/iterator.rs +++ b/src/context/iterator.rs @@ -315,6 +315,7 @@ impl<'c, L: 'c + Iterator, I: 'c + RawLock + Lockable, O> LockingI /// let last = iter.lock_last().unwrap(); /// assert_eq!(**last, 8); /// ``` + // I'm honestly not sure why anyone would use this pub fn lock_last(self) -> Option::Guard<'c>, ThreadKey>> { self.iterator.last().map(|lock| unsafe { lock.raw_write(); @@ -542,6 +543,12 @@ impl<'c, L: 'c + Iterator, I: 'c + RawLock + Sharable, O> } } +// Most of these methods are wrappers around Iterator methods. I didn't +// implement all of them. Some of them don't make sense for this type of +// collection, like rposition. Many iterator methods also take closures, and I +// wasn't sure if people would want a reference to the lock or the value inside +// the lock. In retrospect, we can't actually allow people to see references to +// the locks, so maybe we should just settle for values inside locks. impl<'l, L: Iterator, O> LockingIterator<'l, L, O> { /// Advances the iterator, without locking the next element in the iterator. /// diff --git a/src/context/tuple.rs b/src/context/tuple.rs index 9bca72e..d2a1b0d 100644 --- a/src/context/tuple.rs +++ b/src/context/tuple.rs @@ -17,6 +17,9 @@ impl<'c, A, B, O> LockingTuple<'c, A, B, O> { } } +// Some day I need to invent variadic generics for Rust to make this easier for +// myself + macro_rules! lock_impl { ($self: expr, $field: tt) => { unsafe { @@ -158,6 +161,10 @@ macro_rules! recurse_iter_impl { }; } +// I created these types to help reduce the complexity of the method return +// types. But now I've added so much functionality that these types are just as +// complicates. Oh well. + type LockReturn<'a, 'context, Guarded, L, C, O> = ( ContextGuard<'a, ::Guard<'a>, ThreadKey>, LockingTuple<'context, L, C, O>, @@ -185,6 +192,7 @@ type RecurseIterReturn<'context, Inner, L, C, O> = LockingIterator< impl LockingTuple<'_, T, C, Outer> { /// Exit out of the current scope of the locking tuple into the parent. + // Luckily, this only needs one implementation pub fn exit(self) -> Outer { self.outer } -- cgit v1.3.1