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

  1. the state does not require a lock to access, or
  2. 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>

source

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>
where T: Deref, T::Target: Sized,

source

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 Derefs 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>

source

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.

source

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).

source

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>
where T: Deref, T::Target: Sized,

source

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.

source

pub fn lock<M>(&mut self) -> <T::Target as LockFor<M>>::Guard<'_>
where T::Target: LockFor<M>, L: LockBefore<M>,

Acquire the given lock.

This requires that M can be locked after L.

source

pub fn lock_and<M>( &mut self ) -> (<T::Target as LockFor<M>>::Guard<'_>, Locked<&T::Target, M>)
where T::Target: LockFor<M>, L: LockBefore<M>,

Acquire the given lock and a new locked context.

This requires that M can be locked after L.

source

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.

source

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.

source

pub fn read_lock<M>(&mut self) -> <T::Target as RwLockFor<M>>::ReadGuard<'_>
where T::Target: RwLockFor<M>, L: LockBefore<M>,

Attempt to acquire the given read lock.

For accessing state via reader/writer locks. This requires that M can be locked after L.

source

pub fn read_lock_and<M>( &mut self ) -> (<T::Target as RwLockFor<M>>::ReadGuard<'_>, Locked<&T::Target, M>)
where T::Target: RwLockFor<M>, L: LockBefore<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.

source

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.

source

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.

source

pub fn write_lock<M>(&mut self) -> <T::Target as RwLockFor<M>>::WriteGuard<'_>
where T::Target: RwLockFor<M>, L: LockBefore<M>,

Attempt to acquire the given write lock.

For accessing state via reader/writer locks. This requires that M can be locked after L.

source

pub fn write_lock_and<M>( &mut self ) -> (<T::Target as RwLockFor<M>>::WriteGuard<'_>, Locked<&T::Target, M>)
where T::Target: RwLockFor<M>, L: LockBefore<M>,

Attempt to acquire the given write lock.

For accessing state via reader/writer locks. This requires that M can be locked after L.

source

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.

source

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.

source

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.

source

pub fn cast<R>(&mut self) -> Locked<&R, L>
where T::Target: AsRef<R>,

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.

source

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

  1. the locked wrapper does not take the type T being locked into account, so there’s no danger of lock ordering being different for T and some other type R,
  2. because the new &R references a part of the original &T, any state that was lockable from &T was lockable from &R, and
  3. the returned Locked instance borrows self 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.

source

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.

source

pub fn copied(&self) -> T::Target
where T::Target: Copy,

Convenience function for accessing copyable state.

This, combined with cast or cast_with, makes it easy to access non-locked state.

source

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());
}
source

pub fn cast_left<'a, X, A: Deref + 'a, B: Deref + 'a, F: FnOnce(&A::Target) -> &X>( &'a mut self, f: F ) -> Locked<OwnedTupleWrapper<&X, &B::Target>, L>
where T: Deref<Target = TupleWrapper<A, B>>,

Casts the left reference of the TupleWrapper deref’ed by T.

source

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::Target, &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>
where T: Deref, T::Target: Sized,

§

type AtLockLevel<'l, M> = Locked<&'l <T as Deref>::Target, M> where M: 'l, T: 'l

The same wrapper at a different lock level.
§

type CastWrapper<X> = Locked<X, L> where X: Deref, X::Target: Sized

The same wrapper with a different locked state.
source§

fn wrap<'l, M>(locked: Locked<&'l T::Target, M>) -> Self::AtLockLevel<'l, M>
where M: 'l, T: 'l,

Wraps Locked into a newtype.
source§

fn wrap_cast<R: Deref>(locked: Locked<R, L>) -> Self::CastWrapper<R>
where R::Target: Sized,

Wraps a Locked into a different wrapper implementation.
source§

fn get_mut(&mut self) -> &mut Locked<T, L>

Gets a mutable reference to the wrapped Locked.
source§

fn get(&self) -> &Locked<T, L>

Gets an immutable reference to the wrapped Locked.

Auto Trait Implementations§

§

impl<T, L> Freeze for Locked<T, L>
where T: Freeze,

§

impl<T, L> RefUnwindSafe for Locked<T, L>

§

impl<T, L> Send for Locked<T, L>
where T: Send, L: Send,

§

impl<T, L> Sync for Locked<T, L>
where T: Sync, L: Sync,

§

impl<T, L> Unpin for Locked<T, L>
where T: Unpin, L: Unpin,

§

impl<T, L> UnwindSafe for Locked<T, L>
where T: UnwindSafe, L: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, L, O> LockedWrapperApi<T, L> for O
where T: Deref, <T as Deref>::Target: Sized, O: LockedWrapper<T, L>,

source§

fn lock<'a, M>(&'a mut self) -> <T::Target as LockFor<M>>::Guard<'a>
where T: 'a, T::Target: LockFor<M>, L: LockBefore<M> + 'a,

source§

fn lock_and<'a, M>( &'a mut self ) -> (<T::Target as LockFor<M>>::Guard<'_>, Self::AtLockLevel<'_, M>)
where T::Target: LockFor<M>, L: LockBefore<M> + 'a,

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,

source§

fn lock_with_and<'a, M, X>( &'a mut self, f: impl FnOnce(&T::Target) -> &X ) -> (X::Guard<'_>, Self::AtLockLevel<'_, M>)
where X: LockFor<M>, L: LockBefore<M> + 'a,

source§

fn read_lock<'a, M>(&'a mut self) -> <T::Target as RwLockFor<M>>::ReadGuard<'a>
where T: 'a, T::Target: RwLockFor<M>, L: LockBefore<M> + 'a,

source§

fn read_lock_and<'a, M>( &'a mut self ) -> (<T::Target as RwLockFor<M>>::ReadGuard<'_>, Self::AtLockLevel<'_, M>)
where T::Target: RwLockFor<M>, L: LockBefore<M> + 'a,

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,

source§

fn read_lock_with_and<'a, M, X>( &'a mut self, f: impl FnOnce(&T::Target) -> &X ) -> (X::ReadGuard<'_>, Self::AtLockLevel<'_, 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>
where T: 'a, T::Target: RwLockFor<M>, L: LockBefore<M> + 'a,

source§

fn write_lock_and<'a, M>( &'a mut self ) -> (<T::Target as RwLockFor<M>>::WriteGuard<'_>, Self::AtLockLevel<'_, M>)
where T::Target: RwLockFor<M>, L: LockBefore<M> + 'a,

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,

source§

fn write_lock_with_and<'a, M, X>( &'a mut self, f: impl FnOnce(&T::Target) -> &X ) -> (X::WriteGuard<'_>, Self::AtLockLevel<'_, M>)
where X: RwLockFor<M>, L: LockBefore<M> + 'a,

source§

fn as_owned(&mut self) -> Self::AtLockLevel<'_, L>

source§

fn cast<'a, R>(&'a mut self) -> Self::CastWrapper<&'a R>
where T: 'a, L: 'a, T::Target: AsRef<R>,

source§

fn cast_with<'a, R>( &'a mut self, f: impl FnOnce(&T::Target) -> &R ) -> Self::CastWrapper<&R>
where T: 'a, L: 'a,

source§

fn cast_locked<'a, M>(&'a mut self) -> Self::AtLockLevel<'_, M>
where L: LockBefore<M> + 'a,

source§

fn copied(&self) -> T::Target
where T::Target: Copy,

source§

fn adopt<'a, N>( &'a mut self, n: &'a N ) -> Self::CastWrapper<OwnedTupleWrapper<&'a T::Target, &'a N>>
where T: 'a, L: 'a,

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<&X, &B::Target>>
where L: 'a, T: Deref<Target = TupleWrapper<A, B>> + 'a,

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::Target, &X>>
where L: 'a, T: Deref<Target = TupleWrapper<A, B>> + 'a,

source§

impl<'a, O, T, L> LockedWrapperUnlockedApi<'a, T, L> for O
where T: 'a, L: 'a, O: LockedWrapper<&'a T, L>,

source§

fn unlocked_access<M>(&self) -> T::Guard<'a>
where T: UnlockedAccess<M>,

source§

fn unlocked_access_with<M, X>( &self, f: impl FnOnce(&'a T) -> &'a X ) -> X::Guard<'a>
where X: UnlockedAccess<M>,

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<B, A> LockBefore<B> for A
where B: LockAfter<A>,