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}