Struct lock_order::Locked
source · pub struct Locked<T, L>(/* private fields */);
Expand description
Enforcement mechanism for lock ordering.
Locked
won’t allow locking that violates the described lock order. It
enforces this by allowing access to state so long as either
- the state does not require a lock to access, or
- the state does require a lock and that lock comes after the current lock level in the global lock order.
In the locking case, acquiring a lock produces the new state and a new
Locked
instance that mutably borrows from the original instance. This
means the original instance can’t be used to acquire new locks until the
new instance leaves scope.
Implementations§
source§impl<'a, T> Locked<&'a T, Unlocked>
impl<'a, T> Locked<&'a T, Unlocked>
sourcepub fn new(t: &'a T) -> Self
pub fn new(t: &'a T) -> Self
Entry point for locked access.
Unlocked
is the “root” lock level and can be acquired before any lock.
This function is equivalent to Locked::new_with_deref
but coerces
the argument to a simple borrow, which is the expected common use case.
source§impl<T> Locked<T, Unlocked>
impl<T> Locked<T, Unlocked>
sourcepub fn new_with_deref(t: T) -> Self
pub fn new_with_deref(t: T) -> Self
Entry point for locked access.
Unlocked
is the “root” lock level and can be acquired before any lock.
Unlike Locked::new
, this function just requires that T
be
Deref
and doesn’t coerce the type. Use this function when creating a
new Locked
from cell-like types.
Prefer Locked::new
in most situations given the coercion to a simple
borrow is generally less surprising. For example, &mut T
also Deref
s
to T
and makes for sometimes hard to pin down compilation errors when
implementing traits for Locked<&State, L>
as opposed to &mut State
.
source§impl<'a, T, L> Locked<&'a T, L>
impl<'a, T, L> Locked<&'a T, L>
sourcepub fn new_locked(t: &'a T) -> Locked<&'a T, L>
pub fn new_locked(t: &'a T) -> Locked<&'a T, L>
Entry point for locked access.
Creates a new Locked
that restricts locking to levels after L
. This
is safe because any acquirable locks must have a total ordering, and
restricting the set of locks doesn’t violate that ordering.
See discussion on Locked::new_with_deref
for when to use this
function versus Locked::new_locked_with_deref
.
sourcepub fn unlocked_access<M>(&self) -> T::Guard<'a>where
T: UnlockedAccess<M>,
pub fn unlocked_access<M>(&self) -> T::Guard<'a>where
T: UnlockedAccess<M>,
Access some state that doesn’t require locking.
This allows access to state that doesn’t require locking (and depends on
UnlockedAccess
to be implemented only in cases where that is true).
sourcepub fn unlocked_access_with<M, X>(
&self,
f: impl FnOnce(&'a T) -> &'a X,
) -> X::Guard<'a>where
X: UnlockedAccess<M>,
pub fn unlocked_access_with<M, X>(
&self,
f: impl FnOnce(&'a T) -> &'a X,
) -> X::Guard<'a>where
X: UnlockedAccess<M>,
Access some state that doesn’t require locking from an internal impl of
UnlockedAccess
.
This allows access to state that doesn’t require locking (and depends on
UnlockedAccess
to be implemented only in cases where that is true).
source§impl<T, L> Locked<T, L>
impl<T, L> Locked<T, L>
sourcepub fn new_locked_with_deref(t: T) -> Locked<T, L>
pub fn new_locked_with_deref(t: T) -> Locked<T, L>
Entry point for locked access.
Creates a new Locked
that restricts locking to levels after L
. This
is safe because any acquirable locks must have a total ordering, and
restricting the set of locks doesn’t violate that ordering.
See discussion on Locked::new_with_deref
for when to use this
function versus Locked::new_locked
.
sourcepub fn lock<M>(&mut self) -> <T::Target as LockFor<M>>::Guard<'_>
pub fn lock<M>(&mut self) -> <T::Target as LockFor<M>>::Guard<'_>
Acquire the given lock.
This requires that M
can be locked after L
.
sourcepub fn lock_and<M>(
&mut self,
) -> (<T::Target as LockFor<M>>::Guard<'_>, Locked<&T::Target, M>)
pub fn lock_and<M>( &mut self, ) -> (<T::Target as LockFor<M>>::Guard<'_>, Locked<&T::Target, M>)
Acquire the given lock and a new locked context.
This requires that M
can be locked after L
.
sourcepub fn lock_with<M, X>(
&mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> X::Guard<'_>where
X: LockFor<M>,
L: LockBefore<M>,
pub fn lock_with<M, X>(
&mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> X::Guard<'_>where
X: LockFor<M>,
L: LockBefore<M>,
Acquire the given lock from an internal impl of LockFor
.
This requires that M
can be locked after L
.
sourcepub fn lock_with_and<M, X>(
&mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> (X::Guard<'_>, Locked<&T::Target, M>)where
X: LockFor<M>,
L: LockBefore<M>,
pub fn lock_with_and<M, X>(
&mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> (X::Guard<'_>, Locked<&T::Target, M>)where
X: LockFor<M>,
L: LockBefore<M>,
Acquire the given lock and a new locked context from an internal impl of
LockFor
.
This requires that M
can be locked after L
.
sourcepub fn read_lock<M>(&mut self) -> <T::Target as RwLockFor<M>>::ReadGuard<'_>
pub fn read_lock<M>(&mut self) -> <T::Target as RwLockFor<M>>::ReadGuard<'_>
Attempt to acquire the given read lock.
For accessing state via reader/writer locks. This requires that M
can
be locked after L
.
sourcepub fn read_lock_and<M>(
&mut self,
) -> (<T::Target as RwLockFor<M>>::ReadGuard<'_>, Locked<&T::Target, M>)
pub fn read_lock_and<M>( &mut self, ) -> (<T::Target as RwLockFor<M>>::ReadGuard<'_>, Locked<&T::Target, M>)
Attempt to acquire the given read lock and a new locked context.
For accessing state via reader/writer locks. This requires that M
can
be locked after L
.
sourcepub fn read_lock_with<M, X>(
&mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> X::ReadGuard<'_>where
X: RwLockFor<M>,
L: LockBefore<M>,
pub fn read_lock_with<M, X>(
&mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> X::ReadGuard<'_>where
X: RwLockFor<M>,
L: LockBefore<M>,
Attempt to acquire the given read lock from an internal impl of
RwLockFor
.
For accessing state via reader/writer locks. This requires that M
can
be locked after L
.
sourcepub fn read_lock_with_and<M, X>(
&mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> (X::ReadGuard<'_>, Locked<&T::Target, M>)where
X: RwLockFor<M>,
L: LockBefore<M>,
pub fn read_lock_with_and<M, X>(
&mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> (X::ReadGuard<'_>, Locked<&T::Target, M>)where
X: RwLockFor<M>,
L: LockBefore<M>,
Attempt to acquire the given read lock and a new locked context from an
internal impl of RwLockFor
.
For accessing state via reader/writer locks. This requires that M
can
be locked after L
.
sourcepub fn write_lock<M>(&mut self) -> <T::Target as RwLockFor<M>>::WriteGuard<'_>
pub fn write_lock<M>(&mut self) -> <T::Target as RwLockFor<M>>::WriteGuard<'_>
Attempt to acquire the given write lock.
For accessing state via reader/writer locks. This requires that M
can
be locked after L
.
sourcepub fn write_lock_and<M>(
&mut self,
) -> (<T::Target as RwLockFor<M>>::WriteGuard<'_>, Locked<&T::Target, M>)
pub fn write_lock_and<M>( &mut self, ) -> (<T::Target as RwLockFor<M>>::WriteGuard<'_>, Locked<&T::Target, M>)
Attempt to acquire the given write lock.
For accessing state via reader/writer locks. This requires that M
can
be locked after L
.
sourcepub fn write_lock_with<M, X>(
&mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> X::WriteGuard<'_>where
X: RwLockFor<M>,
L: LockBefore<M>,
pub fn write_lock_with<M, X>(
&mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> X::WriteGuard<'_>where
X: RwLockFor<M>,
L: LockBefore<M>,
Attempt to acquire the given write lock from an internal impl of
RwLockFor
.
For accessing state via reader/writer locks. This requires that M
can
be locked after L
.
sourcepub fn write_lock_with_and<M, X>(
&mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> (X::WriteGuard<'_>, Locked<&T::Target, M>)where
X: RwLockFor<M>,
L: LockBefore<M>,
pub fn write_lock_with_and<M, X>(
&mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> (X::WriteGuard<'_>, Locked<&T::Target, M>)where
X: RwLockFor<M>,
L: LockBefore<M>,
Attempt to acquire the given write lock from an internal impl of
RwLockFor
.
For accessing state via reader/writer locks. This requires that M
can
be locked after L
.
sourcepub fn as_owned(&mut self) -> Locked<&T::Target, L>
pub fn as_owned(&mut self) -> Locked<&T::Target, L>
Returns an owned Locked
from a current Locked
.
Useful when callers need to have access to an owned Locked
but only
have access to a reference.
This method is a shorthand for self.cast_with(|s| s)
. This is safe
because the returned Locked
instance borrows self
mutably so it
can’t be used until the new instance is dropped.
sourcepub fn cast<R>(&mut self) -> Locked<&R, L>
pub fn cast<R>(&mut self) -> Locked<&R, L>
Narrow the type on which locks can be acquired.
Like cast_with
, but with AsRef
instead of using a callable function.
The same safety arguments apply.
sourcepub fn cast_with<R>(
&mut self,
f: impl FnOnce(&T::Target) -> &R,
) -> Locked<&R, L>
pub fn cast_with<R>( &mut self, f: impl FnOnce(&T::Target) -> &R, ) -> Locked<&R, L>
Narrow the type on which locks can be acquired.
This allows scoping down the state on which locks are acquired. This is safe because
- the locked wrapper does not take the type
T
being locked into account, so there’s no danger of lock ordering being different forT
and some other typeR
, - because the new
&R
references a part of the original&T
, any state that was lockable from&T
was lockable from&R
, and - the returned
Locked
instance borrowsself
mutably so it can’t be used until the new instance is dropped.
This method provides a flexible way to access some state held within the
protected instance of T
by scoping down to an individual field, or
infallibly indexing into a Vec
, slice, or map.
sourcepub fn cast_locked<M>(&mut self) -> Locked<&T::Target, M>where
L: LockBefore<M>,
pub fn cast_locked<M>(&mut self) -> Locked<&T::Target, M>where
L: LockBefore<M>,
Restrict locking as if a lock was acquired.
Like lock_and
but doesn’t actually acquire the lock M
. This is
safe because any locks that could be acquired with the lock M
held can
also be acquired without M
being held.
sourcepub fn copied(&self) -> T::Target
pub fn copied(&self) -> T::Target
Convenience function for accessing copyable state.
This, combined with cast
or cast_with
, makes it easy to access
non-locked state.
sourcepub fn adopt<'a, N>(
&'a mut self,
n: &'a N,
) -> Locked<OwnedTupleWrapper<&'a T::Target, &'a N>, L>
pub fn adopt<'a, N>( &'a mut self, n: &'a N, ) -> Locked<OwnedTupleWrapper<&'a T::Target, &'a N>, L>
Adopts reference n
to the locked context.
This allows access on disjoint structures to adopt the same lock level.
§Examples
use lock_order::{Locked, relation::LockBefore};
struct StateA;
struct StateB;
enum LockX {}
fn adopt_example<L: LockBefore<LockX>>(mut locked: Locked<&StateA, L>, state_b: &StateB) {
let mut locked = locked.adopt(state_b);
// Lock something from `StateB` advancing the lock level to `LockX`.
let (guard, mut locked) = locked.lock_with_and::<LockX, _>(|c| c.right());
// We can get back a `Locked` for `StateA` at the new lock level.
let locked: Locked<&StateA, LockX> = locked.cast_with(|c| c.left());
}
sourcepub fn cast_left<'a, X, A: Deref + 'a, B: Deref + 'a, F: FnOnce(&A::Target) -> &X>(
&'a mut self,
f: F,
) -> Locked<OwnedTupleWrapper<&'a X, &'a B::Target>, L>where
T: Deref<Target = TupleWrapper<A, B>>,
pub fn cast_left<'a, X, A: Deref + 'a, B: Deref + 'a, F: FnOnce(&A::Target) -> &X>(
&'a mut self,
f: F,
) -> Locked<OwnedTupleWrapper<&'a X, &'a B::Target>, L>where
T: Deref<Target = TupleWrapper<A, B>>,
Casts the left reference of the TupleWrapper
deref’ed by T
.
sourcepub fn cast_right<'a, X, A: Deref + 'a, B: Deref + 'a, F: FnOnce(&B::Target) -> &X>(
&'a mut self,
f: F,
) -> Locked<OwnedTupleWrapper<&'a A::Target, &'a X>, L>where
T: Deref<Target = TupleWrapper<A, B>>,
pub fn cast_right<'a, X, A: Deref + 'a, B: Deref + 'a, F: FnOnce(&B::Target) -> &X>(
&'a mut self,
f: F,
) -> Locked<OwnedTupleWrapper<&'a A::Target, &'a X>, L>where
T: Deref<Target = TupleWrapper<A, B>>,
Casts the right reference of the TupleWrapper
deref’ed by T
.
Trait Implementations§
source§impl<T, L> LockedWrapper<T, L> for Locked<T, L>
impl<T, L> LockedWrapper<T, L> for Locked<T, L>
§type AtLockLevel<'l, M> = Locked<&'l <T as Deref>::Target, M>
where
M: 'l,
T: 'l
type AtLockLevel<'l, M> = Locked<&'l <T as Deref>::Target, M> where M: 'l, T: 'l
§type CastWrapper<X> = Locked<X, L>
where
X: Deref,
X::Target: Sized
type CastWrapper<X> = Locked<X, L> where X: Deref, X::Target: Sized
source§fn wrap<'l, M>(locked: Locked<&'l T::Target, M>) -> Self::AtLockLevel<'l, M>where
M: 'l,
T: 'l,
fn wrap<'l, M>(locked: Locked<&'l T::Target, M>) -> Self::AtLockLevel<'l, M>where
M: 'l,
T: 'l,
Locked
into a newtype.Auto Trait Implementations§
impl<T, L> Freeze for Locked<T, L>where
T: Freeze,
impl<T, L> RefUnwindSafe for Locked<T, L>where
T: RefUnwindSafe,
L: RefUnwindSafe,
impl<T, L> Send for Locked<T, L>
impl<T, L> Sync for Locked<T, L>
impl<T, L> Unpin for Locked<T, L>
impl<T, L> UnwindSafe for Locked<T, L>where
T: UnwindSafe,
L: UnwindSafe,
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T, L, O> LockedWrapperApi<T, L> for O
impl<T, L, O> LockedWrapperApi<T, L> for O
source§fn lock_and<'a, M>(
&'a mut self,
) -> (<T::Target as LockFor<M>>::Guard<'a>, Self::AtLockLevel<'a, M>)
fn lock_and<'a, M>( &'a mut self, ) -> (<T::Target as LockFor<M>>::Guard<'a>, Self::AtLockLevel<'a, M>)
Locked::lock_and
.source§fn lock_with<'a, M, X>(
&'a mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> X::Guard<'a>where
T: 'a,
X: LockFor<M>,
L: LockBefore<M> + 'a,
fn lock_with<'a, M, X>(
&'a mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> X::Guard<'a>where
T: 'a,
X: LockFor<M>,
L: LockBefore<M> + 'a,
Locked::lock_with
.source§fn lock_with_and<'a, M, X>(
&'a mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> (X::Guard<'a>, Self::AtLockLevel<'a, M>)where
X: LockFor<M>,
L: LockBefore<M> + 'a,
fn lock_with_and<'a, M, X>(
&'a mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> (X::Guard<'a>, Self::AtLockLevel<'a, M>)where
X: LockFor<M>,
L: LockBefore<M> + 'a,
Locked::lock_with_and
.source§fn read_lock<'a, M>(&'a mut self) -> <T::Target as RwLockFor<M>>::ReadGuard<'a>
fn read_lock<'a, M>(&'a mut self) -> <T::Target as RwLockFor<M>>::ReadGuard<'a>
Locked::read_lock
.source§fn read_lock_and<'a, M>(
&'a mut self,
) -> (<T::Target as RwLockFor<M>>::ReadGuard<'a>, Self::AtLockLevel<'a, M>)
fn read_lock_and<'a, M>( &'a mut self, ) -> (<T::Target as RwLockFor<M>>::ReadGuard<'a>, Self::AtLockLevel<'a, M>)
Locked::read_lock_and
.source§fn read_lock_with<'a, M, X>(
&'a mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> X::ReadGuard<'a>where
T: 'a,
X: RwLockFor<M>,
L: LockBefore<M> + 'a,
fn read_lock_with<'a, M, X>(
&'a mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> X::ReadGuard<'a>where
T: 'a,
X: RwLockFor<M>,
L: LockBefore<M> + 'a,
Locked::read_lock_with
.source§fn read_lock_with_and<'a, M, X>(
&'a mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> (X::ReadGuard<'a>, Self::AtLockLevel<'a, M>)where
X: RwLockFor<M>,
L: LockBefore<M> + 'a,
fn read_lock_with_and<'a, M, X>(
&'a mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> (X::ReadGuard<'a>, Self::AtLockLevel<'a, M>)where
X: RwLockFor<M>,
L: LockBefore<M> + 'a,
source§fn write_lock<'a, M>(
&'a mut self,
) -> <T::Target as RwLockFor<M>>::WriteGuard<'a>
fn write_lock<'a, M>( &'a mut self, ) -> <T::Target as RwLockFor<M>>::WriteGuard<'a>
Locked::write_lock
.source§fn write_lock_and<'a, M>(
&'a mut self,
) -> (<T::Target as RwLockFor<M>>::WriteGuard<'a>, Self::AtLockLevel<'a, M>)
fn write_lock_and<'a, M>( &'a mut self, ) -> (<T::Target as RwLockFor<M>>::WriteGuard<'a>, Self::AtLockLevel<'a, M>)
Locked::write_lock_and
.source§fn write_lock_with<'a, M, X>(
&'a mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> X::WriteGuard<'a>where
T: 'a,
X: RwLockFor<M>,
L: LockBefore<M> + 'a,
fn write_lock_with<'a, M, X>(
&'a mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> X::WriteGuard<'a>where
T: 'a,
X: RwLockFor<M>,
L: LockBefore<M> + 'a,
Locked::write_lock_with
.source§fn write_lock_with_and<'a, M, X>(
&'a mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> (X::WriteGuard<'a>, Self::AtLockLevel<'a, M>)where
X: RwLockFor<M>,
L: LockBefore<M> + 'a,
fn write_lock_with_and<'a, M, X>(
&'a mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> (X::WriteGuard<'a>, Self::AtLockLevel<'a, M>)where
X: RwLockFor<M>,
L: LockBefore<M> + 'a,
source§fn as_owned(&mut self) -> Self::AtLockLevel<'_, L>
fn as_owned(&mut self) -> Self::AtLockLevel<'_, L>
Locked::as_owned
.source§fn cast<'a, R>(&'a mut self) -> Self::CastWrapper<&'a R>
fn cast<'a, R>(&'a mut self) -> Self::CastWrapper<&'a R>
Locked::cast
.source§fn cast_with<'a, R>(
&'a mut self,
f: impl FnOnce(&T::Target) -> &R,
) -> Self::CastWrapper<&'a R>where
T: 'a,
L: 'a,
fn cast_with<'a, R>(
&'a mut self,
f: impl FnOnce(&T::Target) -> &R,
) -> Self::CastWrapper<&'a R>where
T: 'a,
L: 'a,
Locked::cast_with
source§fn cast_locked<'a, M>(&'a mut self) -> Self::AtLockLevel<'a, M>where
L: LockBefore<M> + 'a,
fn cast_locked<'a, M>(&'a mut self) -> Self::AtLockLevel<'a, M>where
L: LockBefore<M> + 'a,
Locked::cast_locked
.source§fn adopt<'a, N>(
&'a mut self,
n: &'a N,
) -> Self::CastWrapper<OwnedTupleWrapper<&'a T::Target, &'a N>>where
T: 'a,
L: 'a,
fn adopt<'a, N>(
&'a mut self,
n: &'a N,
) -> Self::CastWrapper<OwnedTupleWrapper<&'a T::Target, &'a N>>where
T: 'a,
L: 'a,
Locked::adopt
.source§fn cast_left<'a, X, A: Deref + 'a, B: Deref + 'a, F: FnOnce(&A::Target) -> &X>(
&'a mut self,
f: F,
) -> Self::CastWrapper<OwnedTupleWrapper<&'a X, &'a B::Target>>where
L: 'a,
T: Deref<Target = TupleWrapper<A, B>> + 'a,
fn cast_left<'a, X, A: Deref + 'a, B: Deref + 'a, F: FnOnce(&A::Target) -> &X>(
&'a mut self,
f: F,
) -> Self::CastWrapper<OwnedTupleWrapper<&'a X, &'a B::Target>>where
L: 'a,
T: Deref<Target = TupleWrapper<A, B>> + 'a,
Locked::cast_left
.source§fn cast_right<'a, X, A: Deref + 'a, B: Deref + 'a, F: FnOnce(&B::Target) -> &X>(
&'a mut self,
f: F,
) -> Self::CastWrapper<OwnedTupleWrapper<&'a A::Target, &'a X>>where
L: 'a,
T: Deref<Target = TupleWrapper<A, B>> + 'a,
fn cast_right<'a, X, A: Deref + 'a, B: Deref + 'a, F: FnOnce(&B::Target) -> &X>(
&'a mut self,
f: F,
) -> Self::CastWrapper<OwnedTupleWrapper<&'a A::Target, &'a X>>where
L: 'a,
T: Deref<Target = TupleWrapper<A, B>> + 'a,
Locked::cast_right
.source§fn replace<'a, N>(&'a mut self, n: &'a N) -> Self::CastWrapper<&'a N>where
L: 'a,
T: 'a,
fn replace<'a, N>(&'a mut self, n: &'a N) -> Self::CastWrapper<&'a N>where
L: 'a,
T: 'a,
Locked::replace
.source§impl<'a, O, T, L> LockedWrapperUnlockedApi<'a, T, L> for Owhere
T: 'a,
L: 'a,
O: LockedWrapper<&'a T, L>,
impl<'a, O, T, L> LockedWrapperUnlockedApi<'a, T, L> for Owhere
T: 'a,
L: 'a,
O: LockedWrapper<&'a T, L>,
source§fn unlocked_access<M>(&self) -> T::Guard<'a>where
T: UnlockedAccess<M>,
fn unlocked_access<M>(&self) -> T::Guard<'a>where
T: UnlockedAccess<M>,
Locked::unlocked_access
.