Skip to main content

ksync/
kcell.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 crate::lock_token::LockToken;
6use core::marker::PhantomData;
7
8/// A container cell that safe-guards data of type `T` using type-level lock class tracking.
9///
10/// `KCell` holds data that can only be safely accessed (read or written) by proving that the
11/// corresponding mutual exclusion lock of class `Class` is currently held by the current thread
12/// via a `LockToken`.
13#[repr(transparent)]
14pub struct KCell<T, Class> {
15    value: core::cell::UnsafeCell<T>,
16    _marker: PhantomData<Class>,
17}
18
19unsafe impl<T: Send, Class> Sync for KCell<T, Class> {}
20unsafe impl<T: Send, Class> Send for KCell<T, Class> {}
21
22impl<T, Class> KCell<T, Class> {
23    /// Creates a new `KCell` containing the specified `value`.
24    #[inline]
25    pub const fn new(value: T) -> Self {
26        Self { value: core::cell::UnsafeCell::new(value), _marker: PhantomData }
27    }
28
29    /// Access the guarded value immutably using a shared lock token.
30    ///
31    /// # Safety
32    ///
33    /// The caller must guarantee that:
34    /// 1. The provided `LockToken` belongs to the specific lock instance that guards this `KCell`
35    ///    (rather than a different lock of the same lock class `Class`).
36    /// 2. The lock is held continuously for the lifetime of the returned reference `'b`.
37    #[inline]
38    pub unsafe fn get<'b>(&self, _token: &'b LockToken<'_, Class>) -> &'b T {
39        // SAFETY: The caller guarantees that the correct lock instance is held continuously
40        // for the duration of the reference lifetime `'b`, ensuring safe immutable access to
41        // the inner value without data races.
42        unsafe { &*self.value.get() }
43    }
44
45    /// Access the guarded value mutably using a mutable lock token.
46    ///
47    /// # Safety
48    ///
49    /// The caller must guarantee that:
50    /// 1. The provided `LockToken` belongs to the specific lock instance that guards this `KCell`
51    ///    (rather than a different lock of the same lock class `Class`).
52    /// 2. The lock is held continuously for the lifetime of the returned reference `'b`.
53    #[inline]
54    pub unsafe fn get_mut<'b>(&self, _token: &'b mut LockToken<'_, Class>) -> &'b mut T {
55        // SAFETY: The caller guarantees that the correct lock instance is held continuously for the
56        // duration of the reference lifetime `'b`, and the exclusive mutable borrow of the
57        // `LockToken` ensures that no other active borrows of the same cell can co-exist,
58        // permitting safe mutable projection from the inner `UnsafeCell` without aliasing or data
59        // races.
60        unsafe { &mut *self.value.get() }
61    }
62
63    /// Returns a mutable raw pointer to the guarded value.
64    ///
65    /// # Safety
66    ///
67    /// The caller must guarantee that the lock instance guarding this `KCell` is held continuously
68    /// while dereferencing or accessing the returned raw pointer.
69    #[inline]
70    pub unsafe fn as_mut_ptr(&self, _token: &mut LockToken<'_, Class>) -> *mut T {
71        self.value.get()
72    }
73
74    /// Accesses the inner value mutably by bypassing the locking requirements using unique borrow
75    /// ownership.
76    #[inline]
77    pub fn get_inner_mut(&mut self) -> &mut T {
78        self.value.get_mut()
79    }
80
81    /// Unwraps the cell, returning the inner value.
82    #[inline]
83    pub fn into_inner(self) -> T {
84        self.value.into_inner()
85    }
86}
87
88impl<T: Default, Class> Default for KCell<T, Class> {
89    #[inline]
90    fn default() -> Self {
91        Self::new(T::default())
92    }
93}
94
95impl<T, Class> From<T> for KCell<T, Class> {
96    #[inline]
97    fn from(value: T) -> Self {
98        Self::new(value)
99    }
100}
101
102impl<T, Class> AsMut<T> for KCell<T, Class> {
103    #[inline]
104    fn as_mut(&mut self) -> &mut T {
105        self.get_inner_mut()
106    }
107}
108
109impl<T, Class> core::fmt::Debug for KCell<T, Class> {
110    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
111        f.debug_struct("KCell")
112            .field("value", &"<locked>")
113            .field("class", &core::any::type_name::<Class>())
114            .finish()
115    }
116}
117
118/// Creates a `PinInit` wrapper for initializing a `KCell` with an inner initializer.
119#[inline]
120pub fn kcell_init<I, Class>(init: I) -> KCellInit<I, Class> {
121    KCellInit(init, PhantomData)
122}
123
124/// Initializer for `KCell`.
125pub struct KCellInit<I, Class>(I, PhantomData<Class>);
126
127// SAFETY: KCell is repr(transparent) and contains T at the same address.
128// Pinning is preserved because KCell doesn't move T.
129unsafe impl<T, Class, I, E> pin_init::PinInit<KCell<T, Class>, E> for KCellInit<I, Class>
130where
131    I: pin_init::PinInit<T, E>,
132{
133    unsafe fn __pinned_init(self, slot: *mut KCell<T, Class>) -> Result<(), E> {
134        // SAFETY: The caller guarantees slot is valid. KCell is repr(transparent)
135        // so slot has the same address and layout as T.
136        unsafe { self.0.__pinned_init(slot as *mut T) }
137    }
138}
139
140#[cfg(not(feature = "kernel"))]
141#[cfg(test)]
142mod tests {
143    use super::*;
144    use lockdep::LockClass;
145
146    struct MyClass;
147    impl LockClass for MyClass {
148        const ID: *mut core::ffi::c_void = core::ptr::null_mut();
149    }
150
151    #[test]
152    fn test_kcell_default() {
153        let cell: KCell<u32, MyClass> = KCell::default();
154        unsafe {
155            let token = LockToken::new();
156            assert_eq!(*cell.get(&token), 0);
157        }
158    }
159
160    #[test]
161    fn test_kcell_exclusive_access() {
162        let mut cell: KCell<u32, MyClass> = KCell::new(10);
163        *cell.get_inner_mut() = 20;
164        let reference: &mut u32 = cell.as_mut();
165        *reference = 30;
166        let value = cell.into_inner();
167        assert_eq!(value, 30);
168    }
169
170    #[test]
171    fn test_kcell_as_mut_ptr() {
172        let cell: KCell<u32, MyClass> = KCell::new(100u32);
173        unsafe {
174            let mut token = LockToken::new();
175            let ptr = cell.as_mut_ptr(&mut token);
176            assert_eq!(*ptr, 100);
177        }
178    }
179
180    #[test]
181    fn test_kcell_debug() {
182        extern crate std;
183        let cell: KCell<u32, MyClass> = KCell::new(5);
184        let debug_str = std::format!("{:?}", cell);
185        assert!(debug_str.contains("KCell"));
186        assert!(debug_str.contains("<locked>"));
187        assert!(debug_str.contains("MyClass"));
188    }
189
190    #[test]
191    fn test_kcell_init() {
192        let init = unsafe {
193            pin_init::pin_init_from_closure(|slot: *mut u32| {
194                slot.write(42);
195                Ok::<(), core::convert::Infallible>(())
196            })
197        };
198        let cell_init = kcell_init::<_, MyClass>(init);
199
200        pin_init::stack_pin_init!(let cell = cell_init);
201        let cell: core::pin::Pin<&mut KCell<u32, MyClass>> = cell;
202
203        unsafe {
204            let token = LockToken::<MyClass>::new();
205            let val = cell.as_ref().get_ref().get(&token);
206            assert_eq!(*val, 42);
207        }
208    }
209}