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