Skip to main content

fp_library/types/
box_ptr.rs

1//! Owned heap-allocated pointer abstraction using [`Box`].
2//!
3//! Provides trait implementations for using `Box` in the library's pointer abstraction.
4//! `BoxBrand` implements [`Pointer`](crate::classes::Pointer) and
5//! [`ToDynFn`](crate::classes::ToDynFn) but not
6//! [`RefCountedPointer`](crate::classes::RefCountedPointer)
7//! (since `Box<dyn Fn>` is not `Clone`).
8//!
9//! ### Examples
10//!
11//! ```
12//! use fp_library::{
13//! 	brands::*,
14//! 	classes::*,
15//! };
16//!
17//! let ptr = <BoxBrand as Pointer>::new(42);
18//! assert_eq!(*ptr, 42);
19//! ```
20
21#[fp_macros::document_module]
22mod inner {
23	use {
24		crate::{
25			brands::BoxBrand,
26			classes::{
27				Pointer,
28				ToDynFn,
29			},
30		},
31		fp_macros::*,
32	};
33
34	impl Pointer for BoxBrand {
35		type Of<'a, T: ?Sized + 'a> = Box<T>;
36
37		/// Wraps a sized value in a `Box`.
38		#[document_signature]
39		///
40		#[document_type_parameters("The lifetime of the value.", "The type of the value to wrap.")]
41		///
42		#[document_parameters("The value to wrap.")]
43		///
44		#[document_returns("The value wrapped in a `Box`.")]
45		///
46		#[document_examples]
47		///
48		/// ```
49		/// use fp_library::{
50		/// 	brands::*,
51		/// 	classes::*,
52		/// };
53		///
54		/// let ptr = <BoxBrand as Pointer>::new(42);
55		/// assert_eq!(*ptr, 42);
56		/// ```
57		fn new<'a, T: 'a>(value: T) -> Box<T> {
58			Box::new(value)
59		}
60	}
61
62	impl ToDynFn for BoxBrand {
63		/// Coerces a sized closure to a `dyn Fn` wrapped in a `Box`.
64		#[document_signature]
65		///
66		#[document_type_parameters(
67			"The lifetime of the closure.",
68			"The input type of the function.",
69			"The output type of the function."
70		)]
71		///
72		#[document_parameters("The closure to coerce.")]
73		///
74		#[document_returns("The closure wrapped in a `Box` as a trait object.")]
75		///
76		#[document_examples]
77		///
78		/// ```
79		/// use fp_library::{
80		/// 	brands::*,
81		/// 	classes::*,
82		/// };
83		///
84		/// let f = <BoxBrand as ToDynFn>::new(|x: i32| x + 1);
85		/// assert_eq!(f(1), 2);
86		/// ```
87		fn new<'a, A: 'a, B: 'a>(f: impl 'a + Fn(A) -> B) -> Box<dyn 'a + Fn(A) -> B> {
88			Box::new(f)
89		}
90
91		/// Coerces a sized by-reference closure to a `dyn Fn(&A) -> B` wrapped in a `Box`.
92		#[document_signature]
93		///
94		#[document_type_parameters(
95			"The lifetime of the closure.",
96			"The input type (the closure receives `&A`).",
97			"The output type of the function."
98		)]
99		///
100		#[document_parameters("The closure to coerce.")]
101		///
102		#[document_returns("The closure wrapped in a `Box` as a by-reference trait object.")]
103		///
104		#[document_examples]
105		///
106		/// ```
107		/// use fp_library::{
108		/// 	brands::*,
109		/// 	classes::*,
110		/// };
111		///
112		/// let f = <BoxBrand as ToDynFn>::ref_new(|x: &i32| *x + 1);
113		/// assert_eq!(f(&1), 2);
114		/// ```
115		fn ref_new<'a, A: 'a, B: 'a>(f: impl 'a + Fn(&A) -> B) -> Box<dyn 'a + Fn(&A) -> B> {
116			Box::new(f)
117		}
118	}
119}
120
121#[cfg(test)]
122mod tests {
123	use crate::{
124		brands::BoxBrand,
125		classes::{
126			Pointer,
127			ToDynFn,
128			to_dyn_fn::{
129				to_dyn_fn,
130				to_ref_dyn_fn,
131			},
132		},
133	};
134
135	#[test]
136	fn test_box_new() {
137		let ptr = <BoxBrand as Pointer>::new(42);
138		assert_eq!(*ptr, 42);
139	}
140
141	#[test]
142	fn test_box_to_dyn_fn() {
143		let f = <BoxBrand as ToDynFn>::new(|x: i32| x + 1);
144		assert_eq!(f(1), 2);
145	}
146
147	#[test]
148	fn test_box_to_dyn_fn_ref() {
149		let f = <BoxBrand as ToDynFn>::ref_new(|x: &i32| *x + 1);
150		assert_eq!(f(&1), 2);
151	}
152
153	#[test]
154	fn test_box_to_dyn_fn_free_fn() {
155		let f = to_dyn_fn::<BoxBrand, _, _>(|x: i32| x + 1);
156		assert_eq!(f(1), 2);
157	}
158
159	#[test]
160	fn test_box_to_ref_dyn_fn_free_fn() {
161		let f = to_ref_dyn_fn::<BoxBrand, _, _>(|x: &i32| *x + 1);
162		assert_eq!(f(&1), 2);
163	}
164
165	#[test]
166	fn test_box_not_clone() {
167		// Box<dyn Fn> is not Clone, confirming BoxBrand cannot implement RefCountedPointer.
168		let f = <BoxBrand as ToDynFn>::new(|x: i32| x + 1);
169		assert_eq!(f(1), 2);
170		// f.clone() would not compile
171	}
172}