Skip to main content

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}