Skip to main content

fp_library/classes/
function.rs

1//! Wrappers over closures for generic handling of functions in higher-kinded contexts.
2//!
3//! ### Examples
4//!
5//! ```
6//! use fp_library::{
7//! 	brands::*,
8//! 	functions::*,
9//! };
10//!
11//! let f = fn_new::<RcFnBrand, _, _>(|x: i32| x * 2);
12//! assert_eq!(f(5), 10);
13//! ```
14
15#[fp_macros::document_module]
16mod inner {
17	use {
18		crate::classes::{
19			profunctor::*,
20			*,
21		},
22		fp_macros::*,
23		std::ops::Deref,
24	};
25
26	/// A trait for wrappers over closures, allowing for generic handling of functions in higher-kinded contexts.
27	///
28	/// This trait is implemented by "Brand" types (like [`ArcFnBrand`][crate::brands::ArcFnBrand]
29	/// and [`RcFnBrand`][crate::brands::RcFnBrand]) to provide a way to construct
30	/// and type-check wrappers over closures (`Arc<dyn Fn...>`, `Rc<dyn Fn...>`,
31	/// etc.) in a generic context, allowing library users to choose between
32	/// implementations at function call sites.
33	///
34	/// The lifetime `'a` ensures the function doesn't outlive referenced data,
35	/// while generic types `A` and `B` represent the input and output types, respectively.
36	pub trait Function: Category + Strong {
37		/// The type of the function wrapper.
38		///
39		/// This associated type represents the concrete type of the wrapper (e.g., `Rc<dyn Fn(A) -> B>`)
40		/// that dereferences to the underlying closure.
41		type Of<'a, A: 'a, B: 'a>: Deref<Target = dyn 'a + Fn(A) -> B>;
42
43		/// Creates a new function wrapper.
44		///
45		/// This function wraps the provided closure `f` into a function wrapper.
46		#[document_signature]
47		///
48		#[document_type_parameters(
49			"The lifetime of the function and its captured data.",
50			"The input type of the function.",
51			"The output type of the function."
52		)]
53		///
54		#[document_parameters("The closure to wrap.", "The input value to the function.")]
55		#[document_returns("The wrapped function.")]
56		#[document_examples]
57		///
58		/// ```
59		/// use fp_library::{
60		/// 	brands::*,
61		/// 	functions::*,
62		/// };
63		///
64		/// let f = fn_new::<RcFnBrand, _, _>(|x: i32| x * 2);
65		/// assert_eq!(f(5), 10);
66		/// ```
67		fn new<'a, A: 'a, B: 'a>(f: impl 'a + Fn(A) -> B) -> <Self as Function>::Of<'a, A, B>;
68	}
69
70	/// Creates a new function wrapper.
71	///
72	/// Free function version that dispatches to [the type class' associated function][`Function::new`].
73	#[document_signature]
74	///
75	#[document_type_parameters(
76		"The lifetime of the function and its captured data.",
77		"The brand of the function wrapper.",
78		"The input type of the function.",
79		"The output type of the function."
80	)]
81	///
82	#[document_parameters("The closure to wrap.", "The input value to the function.")]
83	#[document_returns("The wrapped function.")]
84	#[document_examples]
85	///
86	/// ```
87	/// use fp_library::{
88	/// 	brands::*,
89	/// 	functions::*,
90	/// };
91	///
92	/// let f = fn_new::<RcFnBrand, _, _>(|x: i32| x * 2);
93	/// assert_eq!(f(5), 10);
94	/// ```
95	pub fn new<'a, Brand, A, B>(f: impl 'a + Fn(A) -> B) -> <Brand as Function>::Of<'a, A, B>
96	where
97		Brand: Function, {
98		Brand::new(f)
99	}
100}
101
102pub use inner::*;