Skip to main content

fp_library/types/
rc_ptr.rs

1use crate::{
2	brands::RcBrand,
3	classes::{
4		pointer::Pointer, ref_counted_pointer::RefCountedPointer,
5		unsized_coercible::UnsizedCoercible,
6	},
7};
8use std::rc::Rc;
9
10impl Pointer for RcBrand {
11	type Of<T: ?Sized> = Rc<T>;
12
13	/// Wraps a sized value in an `Rc`.
14	///
15	/// ### Type Signature
16	///
17	/// `forall a. a -> Rc a`
18	///
19	/// ### Type Parameters
20	///
21	/// * `T`: The type of the value to wrap.
22	///
23	/// ### Parameters
24	///
25	/// * `value`: The value to wrap.
26	///
27	/// ### Returns
28	///
29	/// The value wrapped in an `Rc`.
30	///
31	/// ### Examples
32	///
33	/// ```
34	/// use fp_library::{brands::*, functions::*};
35	///
36	/// let ptr = pointer_new::<RcBrand, _>(42);
37	/// assert_eq!(*ptr, 42);
38	/// ```
39	fn new<T>(value: T) -> Rc<T> {
40		Rc::new(value)
41	}
42}
43
44impl RefCountedPointer for RcBrand {
45	type CloneableOf<T: ?Sized> = Rc<T>;
46
47	/// Wraps a sized value in an `Rc`.
48	///
49	/// ### Type Signature
50	///
51	/// `forall a. a -> Rc a`
52	///
53	/// ### Type Parameters
54	///
55	/// * `T`: The type of the value to wrap.
56	///
57	/// ### Parameters
58	///
59	/// * `value`: The value to wrap.
60	///
61	/// ### Returns
62	///
63	/// The value wrapped in an `Rc`.
64	///
65	/// ### Examples
66	///
67	/// ```
68	/// use fp_library::{brands::*, functions::*};
69	///
70	/// let ptr = ref_counted_pointer_new::<RcBrand, _>(42);
71	/// assert_eq!(*ptr, 42);
72	/// ```
73	fn cloneable_new<T>(value: T) -> Rc<T> {
74		Rc::new(value)
75	}
76
77	/// Attempts to unwrap the inner value if this is the sole reference.
78	///
79	/// ### Type Signature
80	///
81	/// `forall a. Rc a -> Result a (Rc a)`
82	///
83	/// ### Type Parameters
84	///
85	/// * `T`: The type of the wrapped value.
86	///
87	/// ### Parameters
88	///
89	/// * `ptr`: The pointer to attempt to unwrap.
90	///
91	/// ### Returns
92	///
93	/// `Ok(value)` if this is the sole reference, otherwise `Err(ptr)`.
94	///
95	/// ### Examples
96	///
97	/// ```
98	/// use fp_library::{brands::*, functions::*};
99	///
100	/// let ptr = ref_counted_pointer_new::<RcBrand, _>(42);
101	/// assert_eq!(try_unwrap::<RcBrand, _>(ptr), Ok(42));
102	/// ```
103	fn try_unwrap<T>(ptr: Rc<T>) -> Result<T, Rc<T>> {
104		Rc::try_unwrap(ptr)
105	}
106}
107
108impl UnsizedCoercible for RcBrand {
109	/// Coerces a sized closure to a `dyn Fn` wrapped in an `Rc`.
110	///
111	/// ### Type Signature
112	///
113	/// `forall a b. (a -> b) -> Rc (dyn Fn a -> b)`
114	///
115	/// ### Type Parameters
116	///
117	/// * `A`: The input type of the function.
118	/// * `B`: The output type of the function.
119	///
120	/// ### Parameters
121	///
122	/// * `f`: The closure to coerce.
123	///
124	/// ### Returns
125	///
126	/// The closure wrapped in an `Rc` as a trait object.
127	///
128	/// ### Examples
129	///
130	/// ```
131	/// use fp_library::{brands::*, functions::*};
132	///
133	/// let f = coerce_fn::<RcBrand, _, _, _>(|x: i32| x + 1);
134	/// assert_eq!(f(1), 2);
135	/// ```
136	fn coerce_fn<'a, A, B>(f: impl 'a + Fn(A) -> B) -> Rc<dyn 'a + Fn(A) -> B> {
137		Rc::new(f)
138	}
139}
140
141#[cfg(test)]
142mod tests {
143	use super::*;
144	use crate::classes::{pointer::new, ref_counted_pointer::cloneable_new};
145
146	/// Tests that `pointer_new` correctly creates an `Rc` wrapping the value.
147	#[test]
148	fn test_rc_new() {
149		let ptr = new::<RcBrand, _>(42);
150		assert_eq!(*ptr, 42);
151	}
152
153	/// Tests that `ref_counted_pointer_new` correctly creates an `Rc` wrapping the value.
154	#[test]
155	fn test_rc_cloneable_new() {
156		let ptr = cloneable_new::<RcBrand, _>(42);
157		assert_eq!(*ptr, 42);
158	}
159
160	/// Tests that cloning the pointer works as expected (shared ownership).
161	#[test]
162	fn test_rc_clone() {
163		let ptr = cloneable_new::<RcBrand, _>(42);
164		let clone = ptr.clone();
165		assert_eq!(*clone, 42);
166	}
167
168	/// Tests `try_unwrap` behavior:
169	/// - Returns `Ok(value)` when there is only one reference.
170	/// - Returns `Err(ptr)` when there are multiple references.
171	#[test]
172	fn test_rc_try_unwrap() {
173		let ptr = cloneable_new::<RcBrand, _>(42);
174		assert_eq!(RcBrand::try_unwrap(ptr), Ok(42));
175
176		let ptr = cloneable_new::<RcBrand, _>(42);
177		let _clone = ptr.clone();
178		assert!(RcBrand::try_unwrap(ptr).is_err());
179	}
180}