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