xref: /DragonOS/kernel/src/libs/lazy_init.rs (revision 5c9a63df836eedaca33c8c4c600b7aaeb2caf9a6)
176612720Slogin // Copyright (C) DragonOS Community  longjin
276612720Slogin 
376612720Slogin // This program is free software; you can redistribute it and/or
476612720Slogin // modify it under the terms of the GNU General Public License
576612720Slogin // as published by the Free Software Foundation; either version 2
676612720Slogin // of the License, or (at your option) any later version.
776612720Slogin 
876612720Slogin // This program is distributed in the hope that it will be useful,
976612720Slogin // but WITHOUT ANY WARRANTY; without even the implied warranty of
1076612720Slogin // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1176612720Slogin // GNU General Public License for more details.
1276612720Slogin 
1376612720Slogin // You should have received a copy of the GNU General Public License
1476612720Slogin // along with this program; if not, write to the Free Software
1576612720Slogin // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
1676612720Slogin // Or you can visit https://www.gnu.org/licenses/gpl-2.0.html
1776612720Slogin #![allow(dead_code)]
1876612720Slogin 
1976612720Slogin use core::cell::UnsafeCell;
2076612720Slogin use core::fmt::Debug;
2176612720Slogin use core::mem::MaybeUninit;
2276612720Slogin use core::ops::{Deref, DerefMut};
2376612720Slogin use core::sync::atomic::{AtomicBool, Ordering};
2476612720Slogin 
2576612720Slogin use super::spinlock::SpinLock;
2676612720Slogin 
2776612720Slogin /// A wrapper around a value that is initialized lazily.
28*5c9a63dfSlogin pub struct Lazy<T> {
2976612720Slogin     /// The lock that is used to ensure that only one thread calls the init function at the same time.
3076612720Slogin     init_lock: SpinLock<()>,
3176612720Slogin     /// The value that is initialized lazily.
3276612720Slogin     value: UnsafeCell<MaybeUninit<T>>,
3376612720Slogin     /// Whether the value has been initialized.
3476612720Slogin     initialized: AtomicBool,
3576612720Slogin }
3676612720Slogin 
37*5c9a63dfSlogin impl<T> Lazy<T> {
3876612720Slogin     /// Creates a new `Lazy` value that will be initialized with the
3976612720Slogin     /// result of the closure `init`.
new() -> Lazy<T>4076612720Slogin     pub const fn new() -> Lazy<T> {
4176612720Slogin         Lazy {
4276612720Slogin             value: UnsafeCell::new(MaybeUninit::uninit()),
4376612720Slogin             initialized: AtomicBool::new(false),
4476612720Slogin             init_lock: SpinLock::new(()),
4576612720Slogin         }
4676612720Slogin     }
4776612720Slogin 
4876612720Slogin     /// Returns true if the value has been initialized.
4976612720Slogin     #[inline(always)]
initialized(&self) -> bool5076612720Slogin     pub fn initialized(&self) -> bool {
5176612720Slogin         let initialized = self.initialized.load(Ordering::Acquire);
5276612720Slogin         if initialized {
5376612720Slogin             return true;
5476612720Slogin         }
5576612720Slogin         return false;
5676612720Slogin     }
5776612720Slogin 
5876612720Slogin     /// Ensures that this lazy value is initialized. If the value has not
5976612720Slogin     /// yet been initialized, this will raise a panic.
6076612720Slogin     #[inline(always)]
ensure(&self)6176612720Slogin     pub fn ensure(&self) {
6276612720Slogin         if self.initialized() {
6376612720Slogin             return;
6476612720Slogin         }
6576612720Slogin         panic!("Lazy value was not initialized");
6676612720Slogin     }
6776612720Slogin 
init(&self, value: T)6876612720Slogin     pub fn init(&self, value: T) {
6976612720Slogin         assert!(!self.initialized());
7076612720Slogin 
7176612720Slogin         // We need this lock to ensure that only one thread calls the init function at the same time.
7276612720Slogin         let _init_guard = self.init_lock.lock();
7376612720Slogin         // Check again, in case another thread initialized it while we were waiting for the lock.
7476612720Slogin         let initialized = self.initialized();
7576612720Slogin         if initialized {
7676612720Slogin             return;
7776612720Slogin         }
7876612720Slogin         unsafe {
7976612720Slogin             (*self.value.get()).as_mut_ptr().write(value);
8076612720Slogin         }
8176612720Slogin         self.initialized.store(true, Ordering::Release);
8276612720Slogin     }
8376612720Slogin     /// Forces the evaluation of this lazy value and returns a reference to
8476612720Slogin     /// the result. This is equivalent to the `Deref` impl, but is explicit.
8576612720Slogin     /// This will initialize the value if it has not yet been initialized.
get(&self) -> &T8676612720Slogin     pub fn get(&self) -> &T {
8776612720Slogin         self.ensure();
8876612720Slogin         return unsafe { self.get_unchecked() };
8976612720Slogin     }
9076612720Slogin 
9176612720Slogin     /// Returns a reference to the value if it has been initialized.
9276612720Slogin     /// Otherwise, returns `None`.
try_get(&self) -> Option<&T>9376612720Slogin     pub fn try_get(&self) -> Option<&T> {
9476612720Slogin         if self.initialized() {
9576612720Slogin             return Some(unsafe { self.get_unchecked() });
9676612720Slogin         }
9776612720Slogin         return None;
9876612720Slogin     }
9976612720Slogin 
10076612720Slogin     /// Forces the evaluation of this lazy value and returns a mutable
10176612720Slogin     /// reference to the result. This is equivalent to the `DerefMut` impl,
10276612720Slogin     /// but is explicit. This will initialize the value if it has not yet
10376612720Slogin     /// been initialized.
get_mut(&mut self) -> &mut T10476612720Slogin     pub fn get_mut(&mut self) -> &mut T {
10576612720Slogin         self.ensure();
10676612720Slogin         return unsafe { self.get_mut_unchecked() };
10776612720Slogin     }
10876612720Slogin 
10976612720Slogin     #[inline(always)]
get_unchecked(&self) -> &T11076612720Slogin     pub unsafe fn get_unchecked(&self) -> &T {
11176612720Slogin         return &*(*self.value.get()).as_ptr();
11276612720Slogin     }
11376612720Slogin 
11476612720Slogin     #[inline(always)]
get_mut_unchecked(&mut self) -> &mut T11576612720Slogin     pub unsafe fn get_mut_unchecked(&mut self) -> &mut T {
11676612720Slogin         return &mut *(*self.value.get()).as_mut_ptr();
11776612720Slogin     }
11876612720Slogin }
11976612720Slogin 
120*5c9a63dfSlogin impl<T> Deref for Lazy<T> {
12176612720Slogin     type Target = T;
12276612720Slogin 
12376612720Slogin     #[inline(always)]
deref(&self) -> &T12476612720Slogin     fn deref(&self) -> &T {
12576612720Slogin         return self.get();
12676612720Slogin     }
12776612720Slogin }
12876612720Slogin 
129*5c9a63dfSlogin impl<T> DerefMut for Lazy<T> {
13076612720Slogin     #[inline(always)]
deref_mut(&mut self) -> &mut T13176612720Slogin     fn deref_mut(&mut self) -> &mut T {
13276612720Slogin         return self.get_mut();
13376612720Slogin     }
13476612720Slogin }
13576612720Slogin 
136*5c9a63dfSlogin impl<T: Debug> Debug for Lazy<T> {
fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result13776612720Slogin     fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
13876612720Slogin         if let Some(value) = self.try_get() {
13976612720Slogin             return write!(f, "Lazy({:?})", value);
14076612720Slogin         } else {
14176612720Slogin             return write!(f, "Lazy(uninitialized)");
14276612720Slogin         }
14376612720Slogin     }
14476612720Slogin }
14576612720Slogin 
146*5c9a63dfSlogin impl<T> Drop for Lazy<T> {
drop(&mut self)14776612720Slogin     fn drop(&mut self) {
14876612720Slogin         if self.initialized() {
14976612720Slogin             unsafe {
15076612720Slogin                 (*self.value.get()).as_mut_ptr().drop_in_place();
15176612720Slogin             }
15276612720Slogin         }
15376612720Slogin     }
15476612720Slogin }
155*5c9a63dfSlogin 
156*5c9a63dfSlogin unsafe impl<T: Send + Sync> Sync for Lazy<T> {}
157*5c9a63dfSlogin unsafe impl<T: Send> Send for Lazy<T> {}
158