Skip to main content

fp_library/types/
arc_ptr.rs

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