lady_deirdre/sync/
lazy.rs

1////////////////////////////////////////////////////////////////////////////////
2// This file is part of "Lady Deirdre", a compiler front-end foundation       //
3// technology.                                                                //
4//                                                                            //
5// This work is proprietary software with source-available code.              //
6//                                                                            //
7// To copy, use, distribute, or contribute to this work, you must agree to    //
8// the terms of the General License Agreement:                                //
9//                                                                            //
10// https://github.com/Eliah-Lakhin/lady-deirdre/blob/master/EULA.md           //
11//                                                                            //
12// The agreement grants a Basic Commercial License, allowing you to use       //
13// this work in non-commercial and limited commercial products with a total   //
14// gross revenue cap. To remove this commercial limit for one of your         //
15// products, you must acquire a Full Commercial License.                      //
16//                                                                            //
17// If you contribute to the source code, documentation, or related materials, //
18// you must grant me an exclusive license to these contributions.             //
19// Contributions are governed by the "Contributions" section of the General   //
20// License Agreement.                                                         //
21//                                                                            //
22// Copying the work in parts is strictly forbidden, except as permitted       //
23// under the General License Agreement.                                       //
24//                                                                            //
25// If you do not or cannot agree to the terms of this Agreement,              //
26// do not use this work.                                                      //
27//                                                                            //
28// This work is provided "as is", without any warranties, express or implied, //
29// except where such disclaimers are legally invalid.                         //
30//                                                                            //
31// Copyright (c) 2024 Ilya Lakhin (Илья Александрович Лахин).                 //
32// All rights reserved.                                                       //
33////////////////////////////////////////////////////////////////////////////////
34
35use std::{ops::Deref, sync::OnceLock};
36
37/// A value which is initialized on the first access.
38///
39/// Lazy is thread-safe and can be used in statics.
40///
41/// Any dereferencing access will block the thread if another thread is currently
42/// initializes this Lazy.
43///
44/// The first generic parameter `T` is required and specifies the underlying
45/// data type.
46///
47/// The second generic parameter is inferred by the compiler based on the
48/// constructor's callback:
49///
50/// ```
51/// use std::ops::Deref;
52/// use lady_deirdre::sync::Lazy;
53///
54/// static FOO: Lazy<usize> = Lazy::new(|| 10 + 20);
55///
56/// let a: &'static usize = FOO.deref(); // first access implies initialization
57///
58/// assert_eq!(*a, 30);
59/// ```
60///
61/// If you are familiar with
62/// the [once_cell](https://github.com/matklad/once_cell/tree/c48d3c2c01de926228aea2ac1d03672b4ce160c1)
63/// crate, Lady Deirdre's Lazy implements a similar object as
64/// `once_cell::sync::Lazy`, but it is fully built on the standard library
65/// features without any third-party dependencies.
66pub struct Lazy<T: Send + Sync + 'static, F = fn() -> T> {
67    cell: OnceLock<T>,
68    init: F,
69}
70
71impl<T: Send + Sync + 'static> Deref for Lazy<T> {
72    type Target = T;
73
74    #[inline(always)]
75    fn deref(&self) -> &Self::Target {
76        self.cell.get_or_init(self.init)
77    }
78}
79
80impl<T: Send + Sync + 'static> Lazy<T> {
81    /// A constructor of the object.
82    ///
83    /// The constructor is a const function, but the `init` function, which
84    /// initializes the Lazy instance on the first dereferencing, is not
85    /// required to be const function.
86    ///
87    /// The `init` constructor should not dereference not-yet-initialized self
88    /// Lazy directly or indirectly. The exact behavior of recurrent
89    /// referencing is not specified, but usually leads to runtime deadlocks and
90    /// may panic on some platforms.
91    #[inline(always)]
92    pub const fn new(init: fn() -> T) -> Self {
93        Self {
94            cell: OnceLock::new(),
95            init,
96        }
97    }
98}