xref: /DragonOS/kernel/src/libs/lazy_init.rs (revision 766127209ee49465a8086cfd0bec90d8b79a96c0)
1*76612720Slogin // Copyright (C) DragonOS Community  longjin
2*76612720Slogin 
3*76612720Slogin // This program is free software; you can redistribute it and/or
4*76612720Slogin // modify it under the terms of the GNU General Public License
5*76612720Slogin // as published by the Free Software Foundation; either version 2
6*76612720Slogin // of the License, or (at your option) any later version.
7*76612720Slogin 
8*76612720Slogin // This program is distributed in the hope that it will be useful,
9*76612720Slogin // but WITHOUT ANY WARRANTY; without even the implied warranty of
10*76612720Slogin // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11*76612720Slogin // GNU General Public License for more details.
12*76612720Slogin 
13*76612720Slogin // You should have received a copy of the GNU General Public License
14*76612720Slogin // along with this program; if not, write to the Free Software
15*76612720Slogin // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16*76612720Slogin // Or you can visit https://www.gnu.org/licenses/gpl-2.0.html
17*76612720Slogin #![allow(dead_code)]
18*76612720Slogin 
19*76612720Slogin use core::cell::UnsafeCell;
20*76612720Slogin use core::fmt::Debug;
21*76612720Slogin use core::mem::MaybeUninit;
22*76612720Slogin use core::ops::{Deref, DerefMut};
23*76612720Slogin use core::sync::atomic::{AtomicBool, Ordering};
24*76612720Slogin 
25*76612720Slogin use super::spinlock::SpinLock;
26*76612720Slogin 
27*76612720Slogin /// A wrapper around a value that is initialized lazily.
28*76612720Slogin /// The value is initialized the first time it is accessed.
29*76612720Slogin /// This is useful for initializing values that are expensive to initialize.
30*76612720Slogin /// The value is initialized using the provided closure.
31*76612720Slogin /// The closure is only called once, and the result is cached.
32*76612720Slogin /// The value is not initialized if it is never accessed.
33*76612720Slogin pub struct Lazy<T: Sync> {
34*76612720Slogin     /// The lock that is used to ensure that only one thread calls the init function at the same time.
35*76612720Slogin     init_lock: SpinLock<()>,
36*76612720Slogin     /// The value that is initialized lazily.
37*76612720Slogin     value: UnsafeCell<MaybeUninit<T>>,
38*76612720Slogin     /// Whether the value has been initialized.
39*76612720Slogin     initialized: AtomicBool,
40*76612720Slogin }
41*76612720Slogin 
42*76612720Slogin impl<T: Sync> Lazy<T> {
43*76612720Slogin     /// Creates a new `Lazy` value that will be initialized with the
44*76612720Slogin     /// result of the closure `init`.
45*76612720Slogin     pub const fn new() -> Lazy<T> {
46*76612720Slogin         Lazy {
47*76612720Slogin             value: UnsafeCell::new(MaybeUninit::uninit()),
48*76612720Slogin             initialized: AtomicBool::new(false),
49*76612720Slogin             init_lock: SpinLock::new(()),
50*76612720Slogin         }
51*76612720Slogin     }
52*76612720Slogin 
53*76612720Slogin     /// Returns true if the value has been initialized.
54*76612720Slogin     #[inline(always)]
55*76612720Slogin     pub fn initialized(&self) -> bool {
56*76612720Slogin         let initialized = self.initialized.load(Ordering::Acquire);
57*76612720Slogin         if initialized {
58*76612720Slogin             return true;
59*76612720Slogin         }
60*76612720Slogin         return false;
61*76612720Slogin     }
62*76612720Slogin 
63*76612720Slogin     /// Ensures that this lazy value is initialized. If the value has not
64*76612720Slogin     /// yet been initialized, this will raise a panic.
65*76612720Slogin     #[inline(always)]
66*76612720Slogin     pub fn ensure(&self) {
67*76612720Slogin         if self.initialized() {
68*76612720Slogin             return;
69*76612720Slogin         }
70*76612720Slogin         panic!("Lazy value was not initialized");
71*76612720Slogin     }
72*76612720Slogin 
73*76612720Slogin     pub fn init(&self, value: T) {
74*76612720Slogin         assert!(!self.initialized());
75*76612720Slogin 
76*76612720Slogin         // We need this lock to ensure that only one thread calls the init function at the same time.
77*76612720Slogin         let _init_guard = self.init_lock.lock();
78*76612720Slogin         // Check again, in case another thread initialized it while we were waiting for the lock.
79*76612720Slogin         let initialized = self.initialized();
80*76612720Slogin         if initialized {
81*76612720Slogin             return;
82*76612720Slogin         }
83*76612720Slogin         unsafe {
84*76612720Slogin             (*self.value.get()).as_mut_ptr().write(value);
85*76612720Slogin         }
86*76612720Slogin         self.initialized.store(true, Ordering::Release);
87*76612720Slogin     }
88*76612720Slogin     /// Forces the evaluation of this lazy value and returns a reference to
89*76612720Slogin     /// the result. This is equivalent to the `Deref` impl, but is explicit.
90*76612720Slogin     /// This will initialize the value if it has not yet been initialized.
91*76612720Slogin     pub fn get(&self) -> &T {
92*76612720Slogin         self.ensure();
93*76612720Slogin         return unsafe { self.get_unchecked() };
94*76612720Slogin     }
95*76612720Slogin 
96*76612720Slogin     /// Returns a reference to the value if it has been initialized.
97*76612720Slogin     /// Otherwise, returns `None`.
98*76612720Slogin     pub fn try_get(&self) -> Option<&T> {
99*76612720Slogin         if self.initialized() {
100*76612720Slogin             return Some(unsafe { self.get_unchecked() });
101*76612720Slogin         }
102*76612720Slogin         return None;
103*76612720Slogin     }
104*76612720Slogin 
105*76612720Slogin     /// Forces the evaluation of this lazy value and returns a mutable
106*76612720Slogin     /// reference to the result. This is equivalent to the `DerefMut` impl,
107*76612720Slogin     /// but is explicit. This will initialize the value if it has not yet
108*76612720Slogin     /// been initialized.
109*76612720Slogin     pub fn get_mut(&mut self) -> &mut T {
110*76612720Slogin         self.ensure();
111*76612720Slogin         return unsafe { self.get_mut_unchecked() };
112*76612720Slogin     }
113*76612720Slogin 
114*76612720Slogin     #[inline(always)]
115*76612720Slogin     pub unsafe fn get_unchecked(&self) -> &T {
116*76612720Slogin         return &*(*self.value.get()).as_ptr();
117*76612720Slogin     }
118*76612720Slogin 
119*76612720Slogin     #[inline(always)]
120*76612720Slogin     pub unsafe fn get_mut_unchecked(&mut self) -> &mut T {
121*76612720Slogin         return &mut *(*self.value.get()).as_mut_ptr();
122*76612720Slogin     }
123*76612720Slogin }
124*76612720Slogin 
125*76612720Slogin impl<T: Sync> Deref for Lazy<T> {
126*76612720Slogin     type Target = T;
127*76612720Slogin 
128*76612720Slogin     #[inline(always)]
129*76612720Slogin     fn deref(&self) -> &T {
130*76612720Slogin         return self.get();
131*76612720Slogin     }
132*76612720Slogin }
133*76612720Slogin 
134*76612720Slogin impl<T: Sync> DerefMut for Lazy<T> {
135*76612720Slogin     #[inline(always)]
136*76612720Slogin     fn deref_mut(&mut self) -> &mut T {
137*76612720Slogin         return self.get_mut();
138*76612720Slogin     }
139*76612720Slogin }
140*76612720Slogin 
141*76612720Slogin impl<T: Sync + Debug> Debug for Lazy<T> {
142*76612720Slogin     fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
143*76612720Slogin         if let Some(value) = self.try_get() {
144*76612720Slogin             return write!(f, "Lazy({:?})", value);
145*76612720Slogin         } else {
146*76612720Slogin             return write!(f, "Lazy(uninitialized)");
147*76612720Slogin         }
148*76612720Slogin     }
149*76612720Slogin }
150*76612720Slogin 
151*76612720Slogin impl<T: Sync> Drop for Lazy<T> {
152*76612720Slogin     fn drop(&mut self) {
153*76612720Slogin         if self.initialized() {
154*76612720Slogin             unsafe {
155*76612720Slogin                 (*self.value.get()).as_mut_ptr().drop_in_place();
156*76612720Slogin             }
157*76612720Slogin         }
158*76612720Slogin     }
159*76612720Slogin }
160