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}