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