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}