fp_library/types/
once_lock.rs

1//! OnceLock wrapper.
2//!
3//! This module defines the [`OnceLockBrand`] struct, which provides implementations for [`OnceLock`].
4//! It implements [`Once`].
5
6use crate::{Apply, brands::OnceLockBrand, classes::once::Once, impl_kind, kinds::*};
7use std::sync::OnceLock;
8
9impl_kind! {
10	for OnceLockBrand {
11		type Of<A> = OnceLock<A>;
12	}
13}
14
15impl Once for OnceLockBrand {
16	type Of<A> = Apply!(<Self as Kind!( type Of<T>; )>::Of<A>);
17
18	/// Creates a new, uninitialized `Once` container.
19	///
20	/// This method creates a new instance of the `OnceLock` that is initially empty.
21	///
22	/// ### Type Signature
23	///
24	/// `forall a. Once OnceLockBrand => () -> OnceLock a`
25	///
26	/// ### Type Parameters
27	///
28	/// * `A`: The type of the value to be stored in the container.
29	///
30	/// ### Returns
31	///
32	/// A new, empty `OnceLock`.
33	///
34	/// ### Examples
35	///
36	/// ```
37	/// use fp_library::classes::once::Once;
38	/// use fp_library::brands::OnceLockBrand;
39	///
40	/// let cell = <OnceLockBrand as Once>::new::<i32>();
41	/// assert_eq!(<OnceLockBrand as Once>::get(&cell), None);
42	/// ```
43	fn new<A>() -> <Self as Once>::Of<A> {
44		OnceLock::new()
45	}
46
47	/// Gets a reference to the value if it has been initialized.
48	///
49	/// This method returns a reference to the value stored in the `OnceLock` if it has been initialized, otherwise it returns `None`.
50	///
51	/// ### Type Signature
52	///
53	/// `forall a. Once OnceLockBrand => OnceLock a -> Option a`
54	///
55	/// ### Type Parameters
56	///
57	/// * `A`: The type of the value stored in the container.
58	///
59	/// ### Parameters
60	///
61	/// * `a`: The `OnceLock`.
62	///
63	/// ### Returns
64	///
65	/// A reference to the value, or `None` if uninitialized.
66	///
67	/// ### Examples
68	///
69	/// ```
70	/// use fp_library::classes::once::Once;
71	/// use fp_library::brands::OnceLockBrand;
72	///
73	/// let cell = <OnceLockBrand as Once>::new::<i32>();
74	/// assert_eq!(<OnceLockBrand as Once>::get(&cell), None);
75	/// <OnceLockBrand as Once>::set(&cell, 42).unwrap();
76	/// assert_eq!(<OnceLockBrand as Once>::get(&cell), Some(&42));
77	/// ```
78	fn get<A>(a: &<Self as Once>::Of<A>) -> Option<&A> {
79		OnceLock::get(a)
80	}
81
82	/// Gets a mutable reference to the value if it has been initialized.
83	///
84	/// This method returns a mutable reference to the value stored in the `OnceLock` if it has been initialized, otherwise it returns `None`.
85	///
86	/// ### Type Signature
87	///
88	/// `forall a. Once OnceLockBrand => OnceLock a -> Option a`
89	///
90	/// ### Type Parameters
91	///
92	/// * `A`: The type of the value stored in the container.
93	///
94	/// ### Parameters
95	///
96	/// * `a`: The `OnceLock`.
97	///
98	/// ### Returns
99	///
100	/// A mutable reference to the value, or `None` if uninitialized.
101	///
102	/// ### Examples
103	///
104	/// ```
105	/// use fp_library::classes::once::Once;
106	/// use fp_library::brands::OnceLockBrand;
107	///
108	/// let mut cell = <OnceLockBrand as Once>::new::<i32>();
109	/// <OnceLockBrand as Once>::set(&cell, 42).unwrap();
110	/// if let Some(val) = <OnceLockBrand as Once>::get_mut(&mut cell) {
111	///     *val += 1;
112	/// }
113	/// assert_eq!(<OnceLockBrand as Once>::get_mut(&mut cell), Some(&mut 43));
114	/// ```
115	fn get_mut<A>(a: &mut <Self as Once>::Of<A>) -> Option<&mut A> {
116		OnceLock::get_mut(a)
117	}
118
119	/// Sets the value of the container.
120	///
121	/// This method attempts to set the value of the `OnceLock`. If the `OnceLock` is already initialized, it returns the value in the `Err` variant.
122	///
123	/// ### Type Signature
124	///
125	/// `forall a. Once OnceLockBrand => (OnceLock a, a) -> Result<(), a>`
126	///
127	/// ### Type Parameters
128	///
129	/// * `A`: The type of the value to set.
130	///
131	/// ### Parameters
132	///
133	/// * `a`: The `OnceLock`.
134	/// * `value`: The value to set.
135	///
136	/// ### Returns
137	///
138	/// `Ok(())` on success, or `Err(value)` if already initialized.
139	///
140	/// ### Examples
141	///
142	/// ```
143	/// use fp_library::classes::once::Once;
144	/// use fp_library::brands::OnceLockBrand;
145	///
146	/// let cell = <OnceLockBrand as Once>::new::<i32>();
147	/// assert!(<OnceLockBrand as Once>::set(&cell, 42).is_ok());
148	/// assert!(<OnceLockBrand as Once>::set(&cell, 10).is_err());
149	/// ```
150	fn set<A>(
151		a: &<Self as Once>::Of<A>,
152		value: A,
153	) -> Result<(), A> {
154		OnceLock::set(a, value)
155	}
156
157	/// Gets the value, initializing it with the closure `f` if it is not already initialized.
158	///
159	/// This method returns a reference to the value stored in the `OnceLock`. If the `OnceLock` is not initialized, it initializes it using the provided closure `f` and then returns a reference to the value.
160	///
161	/// ### Type Signature
162	///
163	/// `forall a. Once OnceLockBrand => (OnceLock a, () -> a) -> a`
164	///
165	/// ### Type Parameters
166	///
167	/// * `A`: The type of the value stored in the container.
168	/// * `B`: The type of the initialization function.
169	///
170	/// ### Parameters
171	///
172	/// * `a`: The `OnceLock`.
173	/// * `f`: The initialization function.
174	///
175	/// ### Returns
176	///
177	/// A reference to the value.
178	///
179	/// ### Examples
180	///
181	/// ```
182	/// use fp_library::classes::once::Once;
183	/// use fp_library::brands::OnceLockBrand;
184	///
185	/// let cell = <OnceLockBrand as Once>::new::<i32>();
186	/// assert_eq!(*<OnceLockBrand as Once>::get_or_init(&cell, || 42), 42);
187	/// assert_eq!(*<OnceLockBrand as Once>::get_or_init(&cell, || 10), 42);
188	/// ```
189	fn get_or_init<A, B: FnOnce() -> A>(
190		a: &<Self as Once>::Of<A>,
191		f: B,
192	) -> &A {
193		OnceLock::get_or_init(a, f)
194	}
195
196	/// Consumes the container and returns the value if it has been initialized.
197	///
198	/// This method consumes the `OnceLock` and returns the value stored in it if it has been initialized, otherwise it returns `None`.
199	///
200	/// ### Type Signature
201	///
202	/// `forall a. Once OnceLockBrand => OnceLock a -> Option a`
203	///
204	/// ### Type Parameters
205	///
206	/// * `A`: The type of the value stored in the container.
207	///
208	/// ### Parameters
209	///
210	/// * `a`: The `OnceLock`.
211	///
212	/// ### Returns
213	///
214	/// The value, or `None` if uninitialized.
215	///
216	/// ### Examples
217	///
218	/// ```
219	/// use fp_library::classes::once::Once;
220	/// use fp_library::brands::OnceLockBrand;
221	///
222	/// let cell = <OnceLockBrand as Once>::new::<i32>();
223	/// <OnceLockBrand as Once>::set(&cell, 42).unwrap();
224	/// assert_eq!(<OnceLockBrand as Once>::into_inner(cell), Some(42));
225	/// ```
226	fn into_inner<A>(a: <Self as Once>::Of<A>) -> Option<A> {
227		OnceLock::into_inner(a)
228	}
229
230	/// Takes the value out of the container, leaving it uninitialized.
231	///
232	/// This method takes the value out of the `OnceLock`, leaving the `OnceLock` in an uninitialized state. It returns the value if it was initialized, otherwise it returns `None`.
233	///
234	/// ### Type Signature
235	///
236	/// `forall a. Once OnceLockBrand => OnceLock a -> Option a`
237	///
238	/// ### Type Parameters
239	///
240	/// * `A`: The type of the value stored in the container.
241	///
242	/// ### Parameters
243	///
244	/// * `a`: The `OnceLock`.
245	///
246	/// ### Returns
247	///
248	/// The value, or `None` if uninitialized.
249	///
250	/// ### Examples
251	///
252	/// ```
253	/// use fp_library::classes::once::Once;
254	/// use fp_library::brands::OnceLockBrand;
255	///
256	/// let mut cell = <OnceLockBrand as Once>::new::<i32>();
257	/// <OnceLockBrand as Once>::set(&cell, 42).unwrap();
258	/// assert_eq!(<OnceLockBrand as Once>::take(&mut cell), Some(42));
259	/// assert_eq!(<OnceLockBrand as Once>::take(&mut cell), None);
260	/// ```
261	fn take<A>(a: &mut <Self as Once>::Of<A>) -> Option<A> {
262		OnceLock::take(a)
263	}
264}
265
266#[cfg(test)]
267mod tests {
268	use super::*;
269	use crate::classes::once::Once;
270
271	/// Tests the `Once` trait implementation for `OnceLock`.
272	#[test]
273	fn test_once_lock() {
274		let mut cell = <OnceLockBrand as Once>::new::<i32>();
275		assert_eq!(<OnceLockBrand as Once>::get(&cell), None);
276
277		assert_eq!(<OnceLockBrand as Once>::set(&cell, 42), Ok(()));
278		assert_eq!(<OnceLockBrand as Once>::get(&cell), Some(&42));
279		assert_eq!(<OnceLockBrand as Once>::set(&cell, 100), Err(100));
280		assert_eq!(<OnceLockBrand as Once>::get(&cell), Some(&42));
281
282		let val = <OnceLockBrand as Once>::get_or_init(&cell, || 99);
283		assert_eq!(val, &42);
284
285		let cell2 = <OnceLockBrand as Once>::new::<i32>();
286		let val2 = <OnceLockBrand as Once>::get_or_init(&cell2, || 99);
287		assert_eq!(val2, &99);
288		assert_eq!(<OnceLockBrand as Once>::get(&cell2), Some(&99));
289
290		assert_eq!(<OnceLockBrand as Once>::take(&mut cell), Some(42));
291		assert_eq!(<OnceLockBrand as Once>::get(&cell), None);
292
293		assert_eq!(<OnceLockBrand as Once>::into_inner(cell2), Some(99));
294	}
295}