ksync/lock_token.rs
1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use core::marker::PhantomData;
6
7/// A token proving that a lock of lock class `Class` is currently held by the current thread.
8///
9/// This token acts as a static proof to permit type-safe borrow access to cell values guarded by
10/// this lock class (via `KCell`).
11#[repr(transparent)]
12pub struct LockToken<'a, Class> {
13 _marker: PhantomData<(&'a Class, *const ())>,
14}
15
16impl<'a, Class> LockToken<'a, Class> {
17 /// Creates a new proof token for the lock class `Class`.
18 ///
19 /// # Safety
20 ///
21 /// The caller must guarantee that the mutual exclusion lock associated with this lock class is
22 /// currently held by the current thread and that the lifetime `'a` is bounded to the duration
23 /// of the lock being held. Creating a token when the lock is not held, or letting the token
24 /// outlive the lock hold duration, can lead to concurrent mutation or data races, which is
25 /// undefined behavior.
26 #[inline]
27 pub unsafe fn new() -> Self {
28 Self { _marker: PhantomData }
29 }
30
31 /// Reborrows this exclusive lock token with its lifetime shortened to the borrow duration `'b`.
32 #[inline]
33 pub fn reborrow<'b>(&'b mut self) -> &'b mut LockToken<'b, Class> {
34 // SAFETY: `LockToken` is a zero-sized type (ZST) with alignment 1. Since `&'b mut self`
35 // requires `'a: 'b`, the lock is held for at least `'b`, and `self` is borrowed
36 // exclusively for `'b`.
37 unsafe { &mut *core::ptr::from_mut(self).cast::<LockToken<'b, Class>>() }
38 }
39
40 /// Combines two exclusive lock tokens into a single composite lock token proving exclusive
41 /// ownership of both lock classes simultaneously for the borrow duration `'b`.
42 #[inline]
43 pub fn join<'b, 'a2, C2>(
44 &'b mut self,
45 _other: &'b mut LockToken<'a2, C2>,
46 ) -> &'b mut LockToken<'b, (Class, C2)> {
47 // SAFETY: `LockToken` is a zero-sized type (ZST) with alignment 1. Casting `self` to a
48 // mutable reference of the composite `LockToken` ZST with lifetime `'b` is valid and
49 // borrows both `self` and `_other` exclusively for `'b`.
50 unsafe { &mut *(self as *mut Self as *mut LockToken<'b, (Class, C2)>) }
51 }
52}
53
54/// Type-level index marker for exact-match lock token access.
55#[doc(hidden)]
56pub struct TokenIndexHere;
57
58/// Type-level index marker for multi-lock tuple projections and permutations.
59#[doc(hidden)]
60pub struct TokenIndex<const N: usize>;
61
62/// Trait implemented by lock tokens that grant shared (read) access to a cell guarded by `Class`.
63///
64/// When a cell is guarded by a single lock `C`, holding `LockToken<'_, C>` grants read access.
65/// When a cell is guarded by multiple locks `(C0, C1, ...)`, holding ANY one of the constituent
66/// locks grants read access, because mutating the cell requires holding ALL constituent locks
67/// simultaneously.
68pub trait LockTokenRead<Class, Idx = TokenIndexHere> {}
69
70/// Trait implemented by lock tokens that grant exclusive (write) access to a cell guarded by
71/// `Class`.
72///
73/// When a cell is guarded by a single lock `C`, holding `&mut LockToken<'_, C>` grants write
74/// access. When a cell is guarded by multiple locks `(C0, C1, ...)`, write access requires a
75/// joined mutable token proving exclusive ownership of ALL constituent locks simultaneously.
76pub trait LockTokenWrite<Class, Idx = TokenIndexHere> {}
77
78impl<Class> LockTokenRead<Class, TokenIndexHere> for LockToken<'_, Class> {}
79impl<Class> LockTokenWrite<Class, TokenIndexHere> for LockToken<'_, Class> {}
80
81// 2-lock tuple `(C0, C1)` read/write implementations.
82impl<C0, C1> LockTokenRead<(C0, C1), TokenIndex<0>> for LockToken<'_, C0> {}
83impl<C0, C1> LockTokenRead<(C0, C1), TokenIndex<1>> for LockToken<'_, C1> {}
84
85impl<C0, C1> LockTokenWrite<(C0, C1), TokenIndex<0>> for LockToken<'_, (C1, C0)> {}
86
87// 3-lock tuple `(C0, C1, C2)` read/write implementations.
88impl<C0, C1, C2> LockTokenRead<(C0, C1, C2), TokenIndex<0>> for LockToken<'_, C0> {}
89impl<C0, C1, C2> LockTokenRead<(C0, C1, C2), TokenIndex<1>> for LockToken<'_, C1> {}
90impl<C0, C1, C2> LockTokenRead<(C0, C1, C2), TokenIndex<2>> for LockToken<'_, C2> {}
91
92impl<C0, C1, C2> LockTokenWrite<(C0, C1, C2), TokenIndex<0>> for LockToken<'_, ((C0, C1), C2)> {}
93
94/// Trait for lock guard types bound to a `Parent` struct instance that hold exclusive ownership
95/// of a lock of class `Class` and can yield a mutable [`LockToken`].
96///
97/// # Safety
98///
99/// Implementors must guarantee that they hold exclusive ownership of the lock of class `Class`
100/// on the `Parent` struct instance at [`ExclusiveLockToken::parent`] for the duration of the
101/// mutable borrow of `self`.
102pub unsafe trait ExclusiveLockToken<Parent: ?Sized, Class> {
103 /// Returns the address of the parent struct instance to which this guard is bound.
104 fn parent(&self) -> *const Parent;
105
106 /// Returns a mutable reference to the underlying [`LockToken`].
107 fn lock_token_mut(&mut self) -> &mut LockToken<'_, Class>;
108}