Skip to main content

fp_library/types/
arc_ptr.rs

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