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}