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