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}