Skip to main content

fp_library/types/
arc_ptr.rs

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