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}