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}