fp_library/types/
once_cell.rs

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