Skip to main content

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}