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