fp_library/types/
arc_ptr.rs

1//! [`ArcBrand`] pointer implementation.
2//!
3//! This module provides implementations of the pointer traits for [`ArcBrand`],
4//! enabling the use of [`Arc`] as a thread-safe reference-counted pointer in the library's
5//! abstraction hierarchy.
6//!
7//! ### Examples
8//!
9//! ```
10//! use fp_library::{brands::*, functions::*};
11//!
12//! let ptr = send_ref_counted_pointer_new::<ArcBrand, _>(42);
13//! assert_eq!(*ptr, 42);
14//! ```
15
16use crate::{
17	brands::ArcBrand,
18	classes::{
19		pointer::Pointer, ref_counted_pointer::RefCountedPointer,
20		send_ref_counted_pointer::SendRefCountedPointer,
21		send_unsized_coercible::SendUnsizedCoercible, thunk_wrapper::ThunkWrapper,
22		unsized_coercible::UnsizedCoercible,
23	},
24};
25use std::sync::{Arc, Mutex};
26
27impl Pointer for ArcBrand {
28	type Of<T: ?Sized> = Arc<T>;
29
30	/// Wraps a sized value in an `Arc`.
31	///
32	/// ### Type Signature
33	///
34	/// `forall a. a -> Arc a`
35	///
36	/// ### Type Parameters
37	///
38	/// * `T`: The type of the value to wrap.
39	///
40	/// ### Parameters
41	///
42	/// * `value`: The value to wrap.
43	///
44	/// ### Returns
45	///
46	/// The value wrapped in an `Arc`.
47	///
48	/// ### Examples
49	///
50	/// ```
51	/// use fp_library::{brands::*, functions::*};
52	///
53	/// let ptr = pointer_new::<ArcBrand, _>(42);
54	/// assert_eq!(*ptr, 42);
55	/// ```
56	fn new<T>(value: T) -> Arc<T> {
57		Arc::new(value)
58	}
59}
60
61impl RefCountedPointer for ArcBrand {
62	type CloneableOf<T: ?Sized> = Arc<T>;
63
64	/// Wraps a sized value in an `Arc`.
65	///
66	/// ### Type Signature
67	///
68	/// `forall a. a -> Arc a`
69	///
70	/// ### Type Parameters
71	///
72	/// * `T`: The type of the value to wrap.
73	///
74	/// ### Parameters
75	///
76	/// * `value`: The value to wrap.
77	///
78	/// ### Returns
79	///
80	/// The value wrapped in an `Arc`.
81	///
82	/// ### Examples
83	///
84	/// ```
85	/// use fp_library::{brands::*, functions::*};
86	///
87	/// let ptr = ref_counted_pointer_new::<ArcBrand, _>(42);
88	/// assert_eq!(*ptr, 42);
89	/// ```
90	fn cloneable_new<T>(value: T) -> Arc<T> {
91		Arc::new(value)
92	}
93
94	/// Attempts to unwrap the inner value if this is the sole reference.
95	///
96	/// ### Type Signature
97	///
98	/// `forall a. Arc a -> Result a (Arc a)`
99	///
100	/// ### Type Parameters
101	///
102	/// * `T`: The type of the wrapped value.
103	///
104	/// ### Parameters
105	///
106	/// * `ptr`: The pointer to attempt to unwrap.
107	///
108	/// ### Returns
109	///
110	/// `Ok(value)` if this is the sole reference, otherwise `Err(ptr)`.
111	///
112	/// ### Examples
113	///
114	/// ```
115	/// use fp_library::{brands::*, functions::*};
116	///
117	/// let ptr = ref_counted_pointer_new::<ArcBrand, _>(42);
118	/// assert_eq!(try_unwrap::<ArcBrand, _>(ptr), Ok(42));
119	/// ```
120	fn try_unwrap<T>(ptr: Arc<T>) -> Result<T, Arc<T>> {
121		Arc::try_unwrap(ptr)
122	}
123}
124
125impl SendRefCountedPointer for ArcBrand {
126	type SendOf<T: ?Sized + Send + Sync> = Arc<T>;
127
128	/// Wraps a sized value in an `Arc`.
129	///
130	/// ### Type Signature
131	///
132	/// `forall a. (Send a, Sync a) => a -> Arc a`
133	///
134	/// ### Type Parameters
135	///
136	/// * `T`: The type of the value to wrap.
137	///
138	/// ### Parameters
139	///
140	/// * `value`: The value to wrap.
141	///
142	/// ### Returns
143	///
144	/// The value wrapped in an `Arc`.
145	///
146	/// ### Examples
147	///
148	/// ```
149	/// use fp_library::{brands::*, functions::*};
150	///
151	/// let ptr = send_ref_counted_pointer_new::<ArcBrand, _>(42);
152	/// assert_eq!(*ptr, 42);
153	/// ```
154	fn send_new<T: Send + Sync>(value: T) -> Arc<T> {
155		Arc::new(value)
156	}
157}
158
159impl UnsizedCoercible for ArcBrand {
160	/// Coerces a sized closure to a `dyn Fn` wrapped in an `Arc`.
161	///
162	/// ### Type Signature
163	///
164	/// `forall a b. (a -> b) -> Arc (dyn Fn a -> b)`
165	///
166	/// ### Type Parameters
167	///
168	/// * `A`: The input type of the function.
169	/// * `B`: The output type of the function.
170	///
171	/// ### Parameters
172	///
173	/// * `f`: The closure to coerce.
174	///
175	/// ### Returns
176	///
177	/// The closure wrapped in an `Arc` as a trait object.
178	///
179	/// ### Examples
180	///
181	/// ```
182	/// use fp_library::{brands::*, functions::*};
183	///
184	/// let f = coerce_fn::<ArcBrand, _, _, _>(|x: i32| x + 1);
185	/// assert_eq!(f(1), 2);
186	/// ```
187	fn coerce_fn<'a, A, B>(f: impl 'a + Fn(A) -> B) -> Arc<dyn 'a + Fn(A) -> B> {
188		Arc::new(f)
189	}
190}
191
192impl SendUnsizedCoercible for ArcBrand {
193	/// Coerces a sized Send+Sync closure to a `dyn Fn + Send + Sync` wrapped in an `Arc`.
194	///
195	/// ### Type Signature
196	///
197	/// `forall a b. (Send (a -> b), Sync (a -> b)) => (a -> b) -> Arc (dyn Fn a -> b + Send + Sync)`
198	///
199	/// ### Type Parameters
200	///
201	/// * `A`: The input type of the function.
202	/// * `B`: The output type of the function.
203	///
204	/// ### Parameters
205	///
206	/// * `f`: The closure to coerce.
207	///
208	/// ### Returns
209	///
210	/// The closure wrapped in an `Arc` as a thread-safe trait object.
211	///
212	/// ### Examples
213	///
214	/// ```
215	/// use fp_library::{brands::*, functions::*};
216	///
217	/// let f = coerce_send_fn::<ArcBrand, _, _, _>(|x: i32| x + 1);
218	/// assert_eq!(f(1), 2);
219	/// ```
220	fn coerce_send_fn<'a, A, B>(
221		f: impl 'a + Fn(A) -> B + Send + Sync
222	) -> Arc<dyn 'a + Fn(A) -> B + Send + Sync> {
223		Arc::new(f)
224	}
225}
226
227impl ThunkWrapper for ArcBrand {
228	type Cell<T> = Mutex<Option<T>>;
229
230	/// Creates a new cell containing the value.
231	///
232	/// ### Type Signature
233	///
234	/// `forall a. Option a -> Mutex (Option a)`
235	///
236	/// ### Type Parameters
237	///
238	/// * `T`: The type of the value.
239	///
240	/// ### Parameters
241	///
242	/// * `value`: The value to wrap.
243	///
244	/// ### Returns
245	///
246	/// A new cell containing the value.
247	///
248	/// ### Examples
249	///
250	/// ```
251	/// use fp_library::{brands::*, functions::*};
252	///
253	/// let cell = thunk_wrapper_new::<ArcBrand, _>(Some(42));
254	/// assert_eq!(thunk_wrapper_take::<ArcBrand, _>(&cell), Some(42));
255	/// ```
256	fn new<T>(value: Option<T>) -> Self::Cell<T> {
257		Mutex::new(value)
258	}
259
260	/// Takes the value out of the cell.
261	///
262	/// ### Type Signature
263	///
264	/// `forall a. Mutex (Option a) -> Option a`
265	///
266	/// ### Type Parameters
267	///
268	/// * `T`: The type of the value.
269	///
270	/// ### Parameters
271	///
272	/// * `cell`: The cell to take the value from.
273	///
274	/// ### Returns
275	///
276	/// The value if it was present, or `None`.
277	///
278	/// ### Examples
279	///
280	/// ```
281	/// use fp_library::{brands::*, functions::*};
282	///
283	/// let cell = thunk_wrapper_new::<ArcBrand, _>(Some(42));
284	/// assert_eq!(thunk_wrapper_take::<ArcBrand, _>(&cell), Some(42));
285	/// assert_eq!(thunk_wrapper_take::<ArcBrand, _>(&cell), None);
286	/// ```
287	fn take<T>(cell: &Self::Cell<T>) -> Option<T> {
288		cell.lock().unwrap().take()
289	}
290}
291
292#[cfg(test)]
293mod tests {
294	use super::*;
295	use crate::classes::{
296		pointer::new, ref_counted_pointer::cloneable_new, send_ref_counted_pointer::send_new,
297	};
298
299	/// Tests that `pointer_new` correctly creates an `Arc` wrapping the value.
300	#[test]
301	fn test_arc_new() {
302		let ptr = new::<ArcBrand, _>(42);
303		assert_eq!(*ptr, 42);
304	}
305
306	/// Tests that `ref_counted_pointer_new` correctly creates an `Arc` wrapping the value.
307	#[test]
308	fn test_arc_cloneable_new() {
309		let ptr = cloneable_new::<ArcBrand, _>(42);
310		assert_eq!(*ptr, 42);
311	}
312
313	/// Tests that `send_ref_counted_pointer_new` correctly creates an `Arc` wrapping the value.
314	#[test]
315	fn test_arc_send_new() {
316		let ptr = send_new::<ArcBrand, _>(42);
317		assert_eq!(*ptr, 42);
318	}
319
320	/// Tests that cloning the pointer works as expected (shared ownership).
321	#[test]
322	fn test_arc_clone() {
323		let ptr = cloneable_new::<ArcBrand, _>(42);
324		let clone = ptr.clone();
325		assert_eq!(*clone, 42);
326	}
327
328	/// Tests `try_unwrap` behavior:
329	/// - Returns `Ok(value)` when there is only one reference.
330	/// - Returns `Err(ptr)` when there are multiple references.
331	#[test]
332	fn test_arc_try_unwrap() {
333		let ptr = cloneable_new::<ArcBrand, _>(42);
334		assert_eq!(ArcBrand::try_unwrap(ptr), Ok(42));
335
336		let ptr = cloneable_new::<ArcBrand, _>(42);
337		let _clone = ptr.clone();
338		assert!(ArcBrand::try_unwrap(ptr).is_err());
339	}
340}