fp_library/types/once_lock.rs
1//! Implementations for [`OnceLock`]
2
3use crate::{Apply, brands::OnceLockBrand, classes::once::Once, impl_kind, kinds::*};
4use std::sync::OnceLock;
5
6impl_kind! {
7 for OnceLockBrand {
8 type Of<A> = OnceLock<A>;
9 }
10}
11
12impl Once for OnceLockBrand {
13 type Of<A> = Apply!(brand: Self, signature: (A));
14
15 /// Creates a new, uninitialized `OnceLock`.
16 ///
17 /// # Type Signature
18 ///
19 /// `forall a. Once OnceLockBrand => () -> OnceLock a`
20 ///
21 /// # Returns
22 ///
23 /// A new, empty `OnceLock`.
24 ///
25 /// # Examples
26 ///
27 /// ```
28 /// use fp_library::classes::once::Once;
29 /// use fp_library::brands::OnceLockBrand;
30 ///
31 /// let cell = <OnceLockBrand as Once>::new::<i32>();
32 /// assert_eq!(<OnceLockBrand as Once>::get(&cell), None);
33 /// ```
34 fn new<A>() -> Apply!(brand: Self, kind: Once, lifetimes: (), types: (A)) {
35 OnceLock::new()
36 }
37
38 /// Gets a reference to the value if it has been initialized.
39 ///
40 /// # Type Signature
41 ///
42 /// `forall a. Once OnceLockBrand => OnceLock a -> Option a`
43 ///
44 /// # Parameters
45 ///
46 /// * `a`: The `OnceLock`.
47 ///
48 /// # Returns
49 ///
50 /// A reference to the value, or `None` if uninitialized.
51 fn get<A>(a: &Apply!(brand: Self, kind: Once, lifetimes: (), types: (A))) -> Option<&A> {
52 OnceLock::get(a)
53 }
54
55 /// Gets a mutable reference to the value if it has been initialized.
56 ///
57 /// # Type Signature
58 ///
59 /// `forall a. Once OnceLockBrand => OnceLock a -> Option a`
60 ///
61 /// # Parameters
62 ///
63 /// * `a`: The `OnceLock`.
64 ///
65 /// # Returns
66 ///
67 /// A mutable reference to the value, or `None` if uninitialized.
68 fn get_mut<A>(
69 a: &mut Apply!(brand: Self, kind: Once, lifetimes: (), types: (A))
70 ) -> Option<&mut A> {
71 OnceLock::get_mut(a)
72 }
73
74 /// Sets the value of the `OnceLock`.
75 ///
76 /// Returns `Ok(())` if the value was set, or `Err(value)` if the cell was already initialized.
77 ///
78 /// # Type Signature
79 ///
80 /// `forall a. Once OnceLockBrand => (OnceLock a, a) -> Result<(), a>`
81 ///
82 /// # Parameters
83 ///
84 /// * `a`: The `OnceLock`.
85 /// * `value`: The value to set.
86 ///
87 /// # Returns
88 ///
89 /// `Ok(())` on success, or `Err(value)` if already initialized.
90 fn set<A>(
91 a: &Apply!(brand: Self, kind: Once, lifetimes: (), types: (A)),
92 value: A,
93 ) -> Result<(), A> {
94 OnceLock::set(a, value)
95 }
96
97 /// Gets the value, initializing it with the closure `f` if it is not already initialized.
98 ///
99 /// # Type Signature
100 ///
101 /// `forall a. Once OnceLockBrand => (OnceLock a, () -> a) -> a`
102 ///
103 /// # Parameters
104 ///
105 /// * `a`: The `OnceLock`.
106 /// * `f`: The initialization function.
107 ///
108 /// # Returns
109 ///
110 /// A reference to the value.
111 fn get_or_init<A, B: FnOnce() -> A>(
112 a: &Apply!(brand: Self, kind: Once, lifetimes: (), types: (A)),
113 f: B,
114 ) -> &A {
115 OnceLock::get_or_init(a, f)
116 }
117
118 /// Consumes the `OnceLock` and returns the value if it has been initialized.
119 ///
120 /// # Type Signature
121 ///
122 /// `forall a. Once OnceLockBrand => OnceLock a -> Option a`
123 ///
124 /// # Parameters
125 ///
126 /// * `a`: The `OnceLock`.
127 ///
128 /// # Returns
129 ///
130 /// The value, or `None` if uninitialized.
131 fn into_inner<A>(a: Apply!(brand: Self, kind: Once, lifetimes: (), types: (A))) -> Option<A> {
132 OnceLock::into_inner(a)
133 }
134
135 /// Takes the value out of the `OnceLock`, leaving it uninitialized.
136 ///
137 /// # Type Signature
138 ///
139 /// `forall a. Once OnceLockBrand => OnceLock a -> Option a`
140 ///
141 /// # Parameters
142 ///
143 /// * `a`: The `OnceLock`.
144 ///
145 /// # Returns
146 ///
147 /// The value, or `None` if uninitialized.
148 fn take<A>(a: &mut Apply!(brand: Self, kind: Once, lifetimes: (), types: (A))) -> Option<A> {
149 OnceLock::take(a)
150 }
151}
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156 use crate::classes::once::Once;
157
158 /// Tests the `Once` trait implementation for `OnceLock`.
159 #[test]
160 fn test_once_lock() {
161 let mut cell = <OnceLockBrand as Once>::new::<i32>();
162 assert_eq!(<OnceLockBrand as Once>::get(&cell), None);
163
164 assert_eq!(<OnceLockBrand as Once>::set(&cell, 42), Ok(()));
165 assert_eq!(<OnceLockBrand as Once>::get(&cell), Some(&42));
166 assert_eq!(<OnceLockBrand as Once>::set(&cell, 100), Err(100));
167 assert_eq!(<OnceLockBrand as Once>::get(&cell), Some(&42));
168
169 let val = <OnceLockBrand as Once>::get_or_init(&cell, || 99);
170 assert_eq!(val, &42);
171
172 let cell2 = <OnceLockBrand as Once>::new::<i32>();
173 let val2 = <OnceLockBrand as Once>::get_or_init(&cell2, || 99);
174 assert_eq!(val2, &99);
175 assert_eq!(<OnceLockBrand as Once>::get(&cell2), Some(&99));
176
177 assert_eq!(<OnceLockBrand as Once>::take(&mut cell), Some(42));
178 assert_eq!(<OnceLockBrand as Once>::get(&cell), None);
179
180 assert_eq!(<OnceLockBrand as Once>::into_inner(cell2), Some(99));
181 }
182}