Skip to main content

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}