Skip to main content

ksync/
konce_cell.rs

1// Copyright 2026 The Fuchsia Authors
2//
3// Use of this source code is governed by a MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT
6
7use core::cell::UnsafeCell;
8use core::marker::PhantomData;
9use core::mem::MaybeUninit;
10
11use crate::lock_token::{LockTokenRead, LockTokenWrite};
12
13/// A cell that provides lazy/one-time initialization synchronized by a lock class `Class`.
14///
15/// `KOnceCell` holds data of type `T` that is uninitialized when created, and can be initialized
16/// at most once by presenting proof (`LockToken`) of holding a lock of class `Class`.
17///
18/// Because access is token-gated by `Class`, initialization is completely free of atomic overhead.
19pub struct KOnceCell<T, Class> {
20    value: UnsafeCell<MaybeUninit<T>>,
21    initialized: UnsafeCell<bool>,
22    _marker: PhantomData<Class>,
23}
24
25// SAFETY: `KOnceCell` synchronizes shared access via `LockToken<Class>`, so it is `Sync` when
26// `T: Send`.
27unsafe impl<T: Send, Class> Sync for KOnceCell<T, Class> {}
28// SAFETY: `KOnceCell` owns `T`, so transferring it across threads is safe when `T: Send`.
29unsafe impl<T: Send, Class> Send for KOnceCell<T, Class> {}
30
31impl<T, Class> KOnceCell<T, Class> {
32    /// Creates a new uninitialized `KOnceCell`.
33    #[inline]
34    pub const fn new() -> Self {
35        Self {
36            value: UnsafeCell::new(MaybeUninit::uninit()),
37            initialized: UnsafeCell::new(false),
38            _marker: PhantomData,
39        }
40    }
41
42    /// Returns `true` if the cell has been initialized.
43    ///
44    /// # Safety
45    ///
46    /// The caller must guarantee that the provided `LockToken` belongs to the specific lock
47    /// instance that guards this `KOnceCell` (rather than a different lock of the same lock class
48    /// `Class`).
49    #[inline]
50    pub unsafe fn is_initialized<Token, Idx>(&self, _token: &Token) -> bool
51    where
52        Token: LockTokenRead<Class, Idx>,
53    {
54        // SAFETY: The caller guarantees that the provided LockToken belongs to the specific lock
55        // instance that guards this cell.
56        unsafe { *self.initialized.get() }
57    }
58
59    /// Accesses the initialized value immutably using a shared lock token.
60    /// Returns `None` if not yet initialized.
61    ///
62    /// # Safety
63    ///
64    /// The caller must guarantee that the provided `LockToken` belongs to the specific lock
65    /// instance that guards this `KOnceCell` (rather than a different lock of the same lock class
66    /// `Class`).
67    #[inline]
68    pub unsafe fn get<'b, Token, Idx>(&self, _token: &'b Token) -> Option<&'b T>
69    where
70        Token: LockTokenRead<Class, Idx>,
71    {
72        // SAFETY: The caller guarantees that the provided LockToken belongs to the specific lock
73        // instance that guards this cell.
74        unsafe {
75            if *self.initialized.get() { Some((*self.value.get()).assume_init_ref()) } else { None }
76        }
77    }
78
79    /// Accesses the initialized value mutably using a mutable lock token.
80    /// Returns `None` if not yet initialized.
81    ///
82    /// # Safety
83    ///
84    /// The caller must guarantee that the provided `LockToken` belongs to the specific lock
85    /// instance that guards this `KOnceCell` (rather than a different lock of the same lock class
86    /// `Class`).
87    #[inline]
88    pub unsafe fn get_mut<'b, Token, Idx>(&self, _token: &'b mut Token) -> Option<&'b mut T>
89    where
90        Token: LockTokenWrite<Class, Idx>,
91    {
92        // SAFETY: The caller guarantees that the provided LockToken belongs to the specific lock
93        // instance that guards this cell, and the exclusive mutable borrow of the `LockToken`
94        // ensures that no other active borrows of the same cell can co-exist.
95        unsafe {
96            if *self.initialized.get() { Some((*self.value.get()).assume_init_mut()) } else { None }
97        }
98    }
99
100    /// Sets the value of the cell if uninitialized, returning `Err(value)` if already initialized.
101    ///
102    /// # Safety
103    ///
104    /// The caller must guarantee that the provided `LockToken` belongs to the specific lock
105    /// instance that guards this `KOnceCell` (rather than a different lock of the same lock class
106    /// `Class`).
107    #[inline]
108    pub unsafe fn set<Token, Idx>(&self, value: T, _token: &mut Token) -> Result<(), T>
109    where
110        Token: LockTokenWrite<Class, Idx>,
111    {
112        // SAFETY: The caller guarantees that the provided LockToken belongs to the specific lock
113        // instance that guards this cell, and the exclusive mutable borrow of the `LockToken`
114        // ensures no concurrent access.
115        unsafe {
116            if *self.initialized.get() {
117                Err(value)
118            } else {
119                let _ = (*self.value.get()).write(value);
120                *self.initialized.get() = true;
121                Ok(())
122            }
123        }
124    }
125
126    /// Initializes the cell with the given closure if uninitialized, returning a mutable reference
127    /// to the contained value.
128    ///
129    /// # Safety
130    ///
131    /// The caller must guarantee that the provided `LockToken` belongs to the specific lock
132    /// instance that guards this `KOnceCell` (rather than a different lock of the same lock class
133    /// `Class`).
134    #[inline]
135    pub unsafe fn get_or_init<'b, Token, Idx>(
136        &self,
137        f: impl FnOnce() -> T,
138        _token: &'b mut Token,
139    ) -> &'b mut T
140    where
141        Token: LockTokenWrite<Class, Idx>,
142    {
143        // SAFETY: The caller guarantees that the provided LockToken belongs to the specific lock
144        // instance that guards this cell, and the exclusive mutable borrow of the `LockToken`
145        // ensures no concurrent access.
146        unsafe {
147            if !*self.initialized.get() {
148                let _ = (*self.value.get()).write(f());
149                *self.initialized.get() = true;
150            }
151            (*self.value.get()).assume_init_mut()
152        }
153    }
154
155    /// Initializes the cell with the given fallible closure if uninitialized, returning a mutable
156    /// reference to the contained value or the error.
157    ///
158    /// # Safety
159    ///
160    /// The caller must guarantee that the provided `LockToken` belongs to the specific lock
161    /// instance that guards this `KOnceCell` (rather than a different lock of the same lock class
162    /// `Class`).
163    #[inline]
164    pub unsafe fn get_or_try_init<'b, E, Token, Idx>(
165        &self,
166        f: impl FnOnce() -> Result<T, E>,
167        _token: &'b mut Token,
168    ) -> Result<&'b mut T, E>
169    where
170        Token: LockTokenWrite<Class, Idx>,
171    {
172        // SAFETY: The caller guarantees that the provided LockToken belongs to the specific lock
173        // instance that guards this cell, and the exclusive mutable borrow of the `LockToken`
174        // ensures no concurrent access.
175        unsafe {
176            if !*self.initialized.get() {
177                let val = f()?;
178                let _ = (*self.value.get()).write(val);
179                *self.initialized.get() = true;
180            }
181            Ok((*self.value.get()).assume_init_mut())
182        }
183    }
184
185    /// Initializes the cell in-place with `PinInit` if uninitialized, returning a mutable reference
186    /// to the contained value or the initialization error.
187    ///
188    /// # Safety
189    ///
190    /// The caller must guarantee that the provided `LockToken` belongs to the specific lock
191    /// instance that guards this `KOnceCell` (rather than a different lock of the same lock class
192    /// `Class`).
193    #[inline]
194    pub unsafe fn get_or_pin_init<'b, E, Token, Idx>(
195        &self,
196        init: impl pin_init::PinInit<T, E>,
197        _token: &'b mut Token,
198    ) -> Result<&'b mut T, E>
199    where
200        Token: LockTokenWrite<Class, Idx>,
201    {
202        // SAFETY: The caller guarantees that the provided LockToken belongs to the specific lock
203        // instance that guards this cell, and the exclusive mutable borrow of the `LockToken`
204        // ensures no concurrent access.
205        unsafe {
206            if !*self.initialized.get() {
207                init.__pinned_init((*self.value.get()).as_mut_ptr())?;
208                *self.initialized.get() = true;
209            }
210            Ok((*self.value.get()).assume_init_mut())
211        }
212    }
213
214    /// Accesses the initialized value immutably without checking for a `LockToken`.
215    /// Returns `None` if not yet initialized.
216    ///
217    /// # Safety
218    ///
219    /// The caller must guarantee that the specific lock instance guarding this `KOnceCell` is held.
220    #[inline]
221    pub unsafe fn get_unchecked(&self) -> Option<&T> {
222        // SAFETY: The caller guarantees that the specific lock instance protecting this cell
223        // is held.
224        unsafe {
225            if *self.initialized.get() { Some((*self.value.get()).assume_init_ref()) } else { None }
226        }
227    }
228
229    /// Accesses the initialized value mutably without checking for a `LockToken`.
230    /// Returns `None` if not yet initialized.
231    ///
232    /// # Safety
233    ///
234    /// The caller must guarantee that the specific lock instance guarding this `KOnceCell` is held
235    /// exclusively without concurrent access.
236    #[allow(clippy::mut_from_ref)]
237    #[inline]
238    pub unsafe fn get_mut_unchecked(&self) -> Option<&mut T> {
239        // SAFETY: The caller guarantees that the specific lock instance protecting this cell is
240        // held exclusively without concurrent access.
241        unsafe {
242            if *self.initialized.get() { Some((*self.value.get()).assume_init_mut()) } else { None }
243        }
244    }
245
246    /// Initializes the cell with the given closure without requiring a `LockToken`.
247    ///
248    /// # Safety
249    ///
250    /// The caller must guarantee that the specific lock instance guarding this `KOnceCell` is held
251    /// exclusively without concurrent access.
252    #[allow(clippy::mut_from_ref)]
253    #[inline]
254    pub unsafe fn get_or_init_unchecked(&self, f: impl FnOnce() -> T) -> &mut T {
255        // SAFETY: The caller guarantees that the specific lock instance protecting this cell is
256        // held exclusively without concurrent access.
257        unsafe {
258            if !*self.initialized.get() {
259                let _ = (*self.value.get()).write(f());
260                *self.initialized.get() = true;
261            }
262            (*self.value.get()).assume_init_mut()
263        }
264    }
265
266    /// Initializes the cell with the given fallible closure without requiring a `LockToken`.
267    ///
268    /// # Safety
269    ///
270    /// The caller must guarantee that the specific lock instance guarding this `KOnceCell` is held
271    /// exclusively without concurrent access.
272    #[allow(clippy::mut_from_ref)]
273    #[inline]
274    pub unsafe fn get_or_try_init_unchecked<E>(
275        &self,
276        f: impl FnOnce() -> Result<T, E>,
277    ) -> Result<&mut T, E> {
278        // SAFETY: The caller guarantees that the specific lock instance protecting this cell is
279        // held exclusively without concurrent access.
280        unsafe {
281            if !*self.initialized.get() {
282                let val = f()?;
283                let _ = (*self.value.get()).write(val);
284                *self.initialized.get() = true;
285            }
286            Ok((*self.value.get()).assume_init_mut())
287        }
288    }
289
290    /// Initializes the cell in-place with `PinInit` without requiring a `LockToken`.
291    ///
292    /// # Safety
293    ///
294    /// The caller must guarantee that the specific lock instance guarding this `KOnceCell` is held
295    /// exclusively without concurrent access.
296    #[allow(clippy::mut_from_ref)]
297    #[inline]
298    pub unsafe fn get_or_pin_init_unchecked<E>(
299        &self,
300        init: impl pin_init::PinInit<T, E>,
301    ) -> Result<&mut T, E> {
302        // SAFETY: The caller guarantees that the specific lock instance protecting this cell is
303        // held exclusively without concurrent access.
304        unsafe {
305            if !*self.initialized.get() {
306                init.__pinned_init((*self.value.get()).as_mut_ptr())?;
307                *self.initialized.get() = true;
308            }
309            Ok((*self.value.get()).assume_init_mut())
310        }
311    }
312
313    /// Accesses the inner value mutably by bypassing locking requirements using unique borrow
314    /// ownership.
315    #[inline]
316    pub fn get_inner_mut(&mut self) -> Option<&mut T> {
317        if *self.initialized.get_mut() {
318            // SAFETY: `initialized` is true, so `value` has been initialized.
319            Some(unsafe { self.value.get_mut().assume_init_mut() })
320        } else {
321            None
322        }
323    }
324
325    /// Unwraps the cell, returning the inner value if initialized.
326    #[inline]
327    pub fn into_inner(mut self) -> Option<T> {
328        if *self.initialized.get_mut() {
329            // SAFETY: `initialized` is true, and resetting `initialized` to false below prevents
330            // `Drop` from dropping the value a second time.
331            let val = unsafe { core::ptr::read(self.value.get_mut().as_ptr()) };
332            *self.initialized.get_mut() = false;
333            Some(val)
334        } else {
335            None
336        }
337    }
338
339    /// Returns a safe guard proxy for this cell using an exclusive lock token.
340    ///
341    /// # Safety
342    ///
343    /// The caller must guarantee that the provided `LockToken` belongs to the specific lock
344    /// instance that guards this `KOnceCell` (rather than a different lock of the same lock class
345    /// `Class`).
346    #[inline]
347    pub unsafe fn guard<'a, Token, Idx>(
348        &'a self,
349        token: &'a mut Token,
350    ) -> KOnceCellGuard<'a, T, Class>
351    where
352        Token: LockTokenWrite<Class, Idx>,
353    {
354        // SAFETY: The caller guarantees that the provided LockToken belongs to the specific lock
355        // instance that guards this cell.
356        unsafe { KOnceCellGuard::new(self, token) }
357    }
358}
359
360impl<T, Class> Default for KOnceCell<T, Class> {
361    #[inline]
362    fn default() -> Self {
363        Self::new()
364    }
365}
366
367impl<T, Class> core::fmt::Debug for KOnceCell<T, Class> {
368    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
369        f.debug_struct("KOnceCell")
370            .field("value", &"<locked>")
371            .field("class", &core::any::type_name::<Class>())
372            .finish()
373    }
374}
375
376impl<T, Class> Drop for KOnceCell<T, Class> {
377    fn drop(&mut self) {
378        if *self.initialized.get_mut() {
379            // SAFETY: `initialized` is true, so `value` contains an initialized `T`.
380            unsafe {
381                self.value.get_mut().assume_init_drop();
382            }
383        }
384    }
385}
386
387/// A safe RAII / proxy guard providing synchronized access to a [`KOnceCell`] protected by a lock.
388///
389/// Created by calling `guard.field_cell()` on a lock guard generated by `#[ksync::guarded]`,
390/// or via [`KOnceCell::guard`].
391pub struct KOnceCellGuard<'a, T, Class> {
392    cell: &'a KOnceCell<T, Class>,
393    _marker: core::marker::PhantomData<(&'a mut (), &'a Class)>,
394}
395
396impl<'a, T, Class> KOnceCellGuard<'a, T, Class> {
397    /// Creates a new `KOnceCellGuard` from a cell reference and an exclusive lock token.
398    ///
399    /// # Safety
400    ///
401    /// The caller must guarantee that the provided `LockToken` belongs to the specific lock
402    /// instance that guards this `KOnceCell` (rather than a different lock of the same lock class
403    /// `Class`).
404    #[inline]
405    pub unsafe fn new<Token, Idx>(cell: &'a KOnceCell<T, Class>, _token: &'a mut Token) -> Self
406    where
407        Token: LockTokenWrite<Class, Idx>,
408    {
409        Self { cell, _marker: core::marker::PhantomData }
410    }
411
412    /// Returns `true` if the cell has been initialized.
413    #[inline]
414    pub fn is_initialized(&self) -> bool {
415        // SAFETY: This guard holds exclusive lock-proven access to `self.cell`.
416        unsafe { self.cell.get_unchecked().is_some() }
417    }
418
419    /// Returns a reference to the initialized value, or `None` if uninitialized.
420    #[inline]
421    pub fn get(&self) -> Option<&T> {
422        // SAFETY: This guard holds exclusive lock-proven access to `self.cell`.
423        unsafe { self.cell.get_unchecked() }
424    }
425
426    /// Returns a mutable reference to the initialized value, or `None` if uninitialized.
427    #[inline]
428    pub fn get_mut(&mut self) -> Option<&mut T> {
429        // SAFETY: The guard guarantees exclusive access while held.
430        unsafe { self.cell.get_mut_unchecked() }
431    }
432
433    /// Sets the value of the cell if uninitialized, returning `Err(value)` if already initialized.
434    #[inline]
435    pub fn set(&mut self, value: T) -> Result<(), T> {
436        // SAFETY: The guard guarantees exclusive access while held.
437        unsafe {
438            if self.cell.get_unchecked().is_some() {
439                Err(value)
440            } else {
441                let _ = (*self.cell.value.get()).write(value);
442                *self.cell.initialized.get() = true;
443                Ok(())
444            }
445        }
446    }
447
448    /// Initializes the cell with the given closure if uninitialized, returning a mutable reference
449    /// to the contained value.
450    #[inline]
451    pub fn get_or_init(&mut self, f: impl FnOnce() -> T) -> &mut T {
452        // SAFETY: The guard guarantees exclusive access while held.
453        unsafe { self.cell.get_or_init_unchecked(f) }
454    }
455
456    /// Initializes the cell with the given fallible closure if uninitialized, returning a mutable
457    /// reference to the contained value or the error.
458    #[inline]
459    pub fn get_or_try_init<E>(&mut self, f: impl FnOnce() -> Result<T, E>) -> Result<&mut T, E> {
460        // SAFETY: The guard guarantees exclusive access while held.
461        unsafe { self.cell.get_or_try_init_unchecked(f) }
462    }
463
464    /// Initializes the cell in-place with `PinInit` if uninitialized, returning a mutable reference
465    /// to the contained value or the initialization error.
466    #[inline]
467    pub fn get_or_pin_init<E>(&mut self, init: impl pin_init::PinInit<T, E>) -> Result<&mut T, E> {
468        // SAFETY: The guard guarantees exclusive access while held.
469        unsafe { self.cell.get_or_pin_init_unchecked(init) }
470    }
471}
472
473impl<T: core::fmt::Debug, Class> core::fmt::Debug for KOnceCellGuard<'_, T, Class> {
474    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
475        f.debug_struct("KOnceCellGuard")
476            .field("value", &self.get())
477            .field("class", &core::any::type_name::<Class>())
478            .finish()
479    }
480}
481
482#[cfg(not(feature = "kernel"))]
483#[cfg(test)]
484mod tests {
485    use super::*;
486    use crate::LockToken;
487    use lockdep::LockClass;
488
489    struct MyClass;
490    impl LockClass for MyClass {
491        const ID: *mut core::ffi::c_void = core::ptr::null_mut();
492    }
493
494    #[test]
495    fn test_konce_cell_init_and_get() {
496        let cell: KOnceCell<u32, MyClass> = KOnceCell::new();
497        // SAFETY: Single-threaded test with exclusive access to `cell`.
498        unsafe {
499            let mut token = LockToken::new();
500            assert!(!cell.is_initialized(&token));
501            assert_eq!(cell.get(&token), None);
502
503            let val = cell.get_or_init(|| 42, &mut token);
504            assert_eq!(*val, 42);
505
506            assert!(cell.is_initialized(&token));
507            assert_eq!(cell.get(&token), Some(&42));
508            assert_eq!(cell.get_mut(&mut token), Some(&mut 42));
509
510            // Subsequent get_or_init does not overwrite
511            let val2 = cell.get_or_init(|| 99, &mut token);
512            assert_eq!(*val2, 42);
513        }
514    }
515
516    #[test]
517    fn test_konce_cell_set() {
518        let cell: KOnceCell<u32, MyClass> = KOnceCell::default();
519        // SAFETY: Single-threaded test with exclusive access to `cell`.
520        unsafe {
521            let mut token = LockToken::new();
522            assert_eq!(cell.set(100, &mut token), Ok(()));
523            assert_eq!(cell.set(200, &mut token), Err(200));
524            assert_eq!(cell.get(&token), Some(&100));
525        }
526    }
527
528    #[test]
529    fn test_konce_cell_try_init() {
530        let cell: KOnceCell<u32, MyClass> = KOnceCell::new();
531        // SAFETY: Single-threaded test with exclusive access to `cell`.
532        unsafe {
533            let mut token = LockToken::new();
534            let err_res = cell.get_or_try_init(|| Err::<u32, _>("failed"), &mut token);
535            assert_eq!(err_res, Err("failed"));
536            assert!(!cell.is_initialized(&token));
537
538            let ok_res = cell.get_or_try_init(|| Ok::<u32, &'static str>(77), &mut token);
539            assert_eq!(ok_res, Ok(&mut 77));
540            assert!(cell.is_initialized(&token));
541        }
542    }
543
544    #[test]
545    fn test_konce_cell_pin_init() {
546        let cell: KOnceCell<u32, MyClass> = KOnceCell::new();
547        // SAFETY: Single-threaded test with exclusive access to `cell`.
548        unsafe {
549            let mut token = LockToken::new();
550            let init = pin_init::pin_init_from_closure(|slot: *mut u32| {
551                slot.write(123);
552                Ok::<(), core::convert::Infallible>(())
553            });
554            let res = cell.get_or_pin_init(init, &mut token);
555            assert_eq!(res, Ok(&mut 123));
556            assert_eq!(cell.get(&token), Some(&123));
557        }
558    }
559
560    #[test]
561    fn test_konce_cell_drop() {
562        use core::sync::atomic::{AtomicUsize, Ordering};
563        static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
564
565        struct DropDetector;
566        impl Drop for DropDetector {
567            fn drop(&mut self) {
568                let _ = DROP_COUNT.fetch_add(1, Ordering::Relaxed);
569            }
570        }
571
572        {
573            let cell: KOnceCell<DropDetector, MyClass> = KOnceCell::new();
574            // SAFETY: Single-threaded test with exclusive access to `cell`.
575            unsafe {
576                let mut token = LockToken::new();
577                let _ = cell.get_or_init(|| DropDetector, &mut token);
578            }
579            assert_eq!(DROP_COUNT.load(Ordering::Relaxed), 0);
580        }
581        assert_eq!(DROP_COUNT.load(Ordering::Relaxed), 1);
582    }
583
584    #[test]
585    fn test_konce_cell_guard() {
586        let cell: KOnceCell<u32, MyClass> = KOnceCell::new();
587        // SAFETY: Single-threaded test with exclusive access to `cell`.
588        unsafe {
589            let mut token = LockToken::new();
590            let mut guard = cell.guard(&mut token);
591            assert!(!guard.is_initialized());
592            assert_eq!(guard.get(), None);
593            assert_eq!(guard.get_mut(), None);
594
595            let val = guard.get_or_init(|| 123);
596            assert_eq!(*val, 123);
597            assert!(guard.is_initialized());
598            assert_eq!(guard.get(), Some(&123));
599            assert_eq!(guard.get_mut(), Some(&mut 123));
600            assert_eq!(guard.set(456), Err(456));
601        }
602    }
603
604    struct SecondClass;
605    impl LockClass for SecondClass {
606        const ID: *mut core::ffi::c_void = core::ptr::null_mut();
607    }
608
609    #[test]
610    fn test_konce_cell_multi_lock() {
611        // 1. Test `is_initialized`, `get`, `set`, `get_mut`, and `guard` with 2 locks.
612        let cell: KOnceCell<u32, (MyClass, SecondClass)> = KOnceCell::new();
613        // SAFETY: Single-threaded test with exclusive access to `cell`.
614        unsafe {
615            let mut t1 = LockToken::<MyClass>::new();
616            let mut t2 = LockToken::<SecondClass>::new();
617
618            assert!(!cell.is_initialized(&t1));
619            assert!(!cell.is_initialized(&t2));
620            assert_eq!(cell.get(&t1), None);
621            assert_eq!(cell.get(&t2), None);
622
623            assert_eq!(cell.set(10, t2.join(&mut t1)), Ok(()));
624            assert!(cell.is_initialized(&t1));
625            assert!(cell.is_initialized(&t2));
626            assert_eq!(cell.get(&t1), Some(&10));
627            assert_eq!(cell.get(&t2), Some(&10));
628
629            *cell.get_mut(t1.join(&mut t2)).unwrap() = 20;
630            assert_eq!(cell.get(&t1), Some(&20));
631
632            *cell.get_mut(t2.join(&mut t1)).unwrap() = 30;
633            assert_eq!(cell.get(&t2), Some(&30));
634
635            let mut g = cell.guard(t2.join(&mut t1));
636            assert_eq!(g.get(), Some(&30));
637            *g.get_mut().unwrap() = 40;
638            assert_eq!(cell.get(&t1), Some(&40));
639        }
640
641        // 2. Test `get_or_init`, `get_or_try_init`, and `get_or_pin_init` with joined tokens.
642        let cell_init: KOnceCell<u32, (MyClass, SecondClass)> = KOnceCell::new();
643        let cell_try: KOnceCell<u32, (MyClass, SecondClass)> = KOnceCell::new();
644        let cell_pin: KOnceCell<u32, (MyClass, SecondClass)> = KOnceCell::new();
645        // SAFETY: Single-threaded test with exclusive access to the cells.
646        unsafe {
647            let mut t1 = LockToken::<MyClass>::new();
648            let mut t2 = LockToken::<SecondClass>::new();
649
650            let val = cell_init.get_or_init(|| 111, t1.join(&mut t2));
651            assert_eq!(*val, 111);
652            assert_eq!(cell_init.get(&t2), Some(&111));
653
654            let err = cell_try.get_or_try_init(|| Err::<u32, _>("err"), t2.join(&mut t1));
655            assert_eq!(err, Err("err"));
656            let ok = cell_try.get_or_try_init(|| Ok::<u32, &'static str>(222), t1.join(&mut t2));
657            assert_eq!(ok, Ok(&mut 222));
658            assert_eq!(cell_try.get(&t1), Some(&222));
659
660            let init = pin_init::pin_init_from_closure(|slot: *mut u32| {
661                slot.write(333);
662                Ok::<(), core::convert::Infallible>(())
663            });
664            let pinned = cell_pin.get_or_pin_init(init, t2.join(&mut t1));
665            assert_eq!(pinned, Ok(&mut 333));
666            assert_eq!(cell_pin.get(&t1), Some(&333));
667        }
668    }
669}