Skip to main content

fp_library/classes/
ref_counted_pointer.rs

1//! Reference-counted pointers with shared ownership and unwrapping capabilities.
2//!
3//! ### Examples
4//!
5//! ```
6//! use fp_library::{brands::*, functions::*};
7//!
8//! let ptr = ref_counted_pointer_new::<RcBrand, _>(42);
9//! let clone = ptr.clone();
10//! assert_eq!(*clone, 42);
11//! ```
12
13use super::Pointer;
14use fp_macros::doc_params;
15use fp_macros::doc_type_params;
16use fp_macros::hm_signature;
17use std::ops::Deref;
18
19/// Extension trait for reference-counted pointers with shared ownership.
20///
21/// Adds `CloneableOf` associated type which is Clone + Deref. This follows
22/// the pattern of `SendCloneableFn` adding `SendOf` to `CloneableFn`.
23pub trait RefCountedPointer: Pointer {
24	/// The cloneable pointer type constructor.
25	///
26	/// For Rc/Arc, this is the same as `Of<T>`.
27	type CloneableOf<T: ?Sized>: Clone + Deref<Target = T>;
28
29	/// Wraps a sized value in a cloneable pointer.
30	///
31	/// ### Type Signature
32	///
33	#[hm_signature]
34	///
35	/// ### Type Parameters
36	///
37	#[doc_type_params("The type of the value to wrap.")]
38	///
39	/// ### Parameters
40	///
41	#[doc_params("The value to wrap.")]
42	///
43	/// ### Returns
44	///
45	/// The value wrapped in the cloneable pointer type.
46	///
47	/// ### Examples
48	///
49	/// ```
50	/// use fp_library::{brands::*, functions::*};
51	///
52	/// let ptr = ref_counted_pointer_new::<RcBrand, _>(42);
53	/// assert_eq!(*ptr, 42);
54	/// ```
55	fn cloneable_new<T>(value: T) -> Self::CloneableOf<T>
56	where
57		Self::CloneableOf<T>: Sized;
58
59	/// Attempts to unwrap the inner value if this is the sole reference.
60	///
61	/// ### Type Signature
62	///
63	#[hm_signature]
64	///
65	/// ### Type Parameters
66	///
67	#[doc_type_params("The type of the wrapped value.")]
68	///
69	/// ### Parameters
70	///
71	#[doc_params("The pointer to attempt to unwrap.")]
72	///
73	/// ### Returns
74	///
75	/// `Ok(value)` if this is the sole reference, otherwise `Err(ptr)`.
76	///
77	/// ### Examples
78	///
79	/// ```
80	/// use fp_library::{brands::*, functions::*};
81	///
82	/// let ptr = ref_counted_pointer_new::<RcBrand, _>(42);
83	/// assert_eq!(try_unwrap::<RcBrand, _>(ptr), Ok(42));
84	///
85	/// let ptr1 = ref_counted_pointer_new::<RcBrand, _>(42);
86	/// let ptr2 = ptr1.clone();
87	/// assert!(try_unwrap::<RcBrand, _>(ptr1).is_err());
88	/// ```
89	fn try_unwrap<T>(ptr: Self::CloneableOf<T>) -> Result<T, Self::CloneableOf<T>>;
90}
91
92/// Attempts to unwrap the inner value if this is the sole reference.
93///
94/// Free function version that dispatches to [the type class' associated function][`RefCountedPointer::try_unwrap`].
95///
96/// ### Type Signature
97///
98#[hm_signature]
99///
100/// ### Type Parameters
101///
102#[doc_type_params("The pointer brand.", "The type of the wrapped value.")]
103///
104/// ### Parameters
105///
106#[doc_params("The pointer to attempt to unwrap.")]
107///
108/// ### Returns
109///
110/// `Ok(value)` if this is the sole reference, otherwise `Err(ptr)`.
111///
112/// ### Examples
113///
114/// ```
115/// use fp_library::{brands::*, functions::*};
116///
117/// let ptr = ref_counted_pointer_new::<RcBrand, _>(42);
118/// assert_eq!(try_unwrap::<RcBrand, _>(ptr), Ok(42));
119///
120/// let ptr1 = ref_counted_pointer_new::<RcBrand, _>(42);
121/// let ptr2 = ptr1.clone();
122/// assert!(try_unwrap::<RcBrand, _>(ptr1).is_err());
123/// ```
124pub fn try_unwrap<P: RefCountedPointer, T>(ptr: P::CloneableOf<T>) -> Result<T, P::CloneableOf<T>> {
125	P::try_unwrap(ptr)
126}
127
128/// Wraps a sized value in a cloneable pointer.
129///
130/// ### Type Signature
131///
132#[hm_signature(RefCountedPointer)]
133///
134/// ### Type Parameters
135///
136#[doc_type_params("The pointer brand.", "The type of the value to wrap.")]
137///
138/// ### Parameters
139///
140#[doc_params("The value to wrap.")]
141///
142/// ### Returns
143///
144/// The value wrapped in the cloneable pointer type.
145///
146/// ### Examples
147///
148/// ```
149/// use fp_library::{brands::*, classes::*, functions::*};
150///
151/// let ptr = ref_counted_pointer_new::<RcBrand, _>(42);
152/// let clone = ptr.clone();
153/// assert_eq!(*clone, 42);
154/// ```
155pub fn cloneable_new<P: RefCountedPointer, T>(value: T) -> P::CloneableOf<T>
156where
157	P::CloneableOf<T>: Sized,
158{
159	P::cloneable_new(value)
160}