Skip to main content

fp_library/classes/
ref_functor_with_index.rs

1//! By-reference variant of [`FunctorWithIndex`](crate::classes::FunctorWithIndex).
2//!
3//! **User story:** "I want to map over a memoized value by reference, with access to the index."
4//!
5//! ### Examples
6//!
7//! ```
8//! use fp_library::{
9//! 	brands::*,
10//! 	classes::ref_functor_with_index::RefFunctorWithIndex,
11//! 	types::*,
12//! };
13//!
14//! let lazy = RcLazy::new(|| 42);
15//! let mapped = <LazyBrand<RcLazyConfig> as RefFunctorWithIndex>::ref_map_with_index(
16//! 	|_, x: &i32| x.to_string(),
17//! 	&lazy,
18//! );
19//! assert_eq!(*mapped.evaluate(), "42");
20//! ```
21
22#[fp_macros::document_module]
23mod inner {
24	use {
25		crate::{
26			classes::*,
27			kinds::*,
28		},
29		fp_macros::*,
30	};
31
32	/// By-reference mapping with index over a structure.
33	///
34	/// Similar to [`FunctorWithIndex`], but the closure receives `&A` instead of `A`.
35	/// This is the honest interface for memoized types like [`Lazy`](crate::types::Lazy)
36	/// that internally hold a cached `&A`.
37	#[kind(type Of<'a, A: 'a>: 'a;)]
38	pub trait RefFunctorWithIndex: RefFunctor + WithIndex {
39		/// Maps a function over the structure by reference, providing the index.
40		#[document_signature]
41		#[document_type_parameters(
42			"The lifetime of the values.",
43			"The type of the elements.",
44			"The type of the result."
45		)]
46		#[document_parameters(
47			"The function to apply to each element's index and reference.",
48			"The structure to map over."
49		)]
50		#[document_returns("The mapped structure.")]
51		#[document_examples]
52		///
53		/// ```
54		/// use fp_library::{
55		/// 	brands::*,
56		/// 	classes::ref_functor_with_index::RefFunctorWithIndex,
57		/// 	types::*,
58		/// };
59		///
60		/// let lazy = RcLazy::new(|| 42);
61		/// let mapped = <LazyBrand<RcLazyConfig> as RefFunctorWithIndex>::ref_map_with_index(
62		/// 	|_, x: &i32| x.to_string(),
63		/// 	&lazy,
64		/// );
65		/// assert_eq!(*mapped.evaluate(), "42");
66		/// ```
67		fn ref_map_with_index<'a, A: 'a, B: 'a>(
68			f: impl Fn(Self::Index, &A) -> B + 'a,
69			fa: &Self::Of<'a, A>,
70		) -> Self::Of<'a, B>;
71	}
72
73	/// Maps a function over a structure by reference with access to the index.
74	///
75	/// Free function version that dispatches to [the type class' associated function][`RefFunctorWithIndex::ref_map_with_index`].
76	#[document_signature]
77	#[document_type_parameters(
78		"The lifetime of the values.",
79		"The brand of the structure.",
80		"The type of the elements.",
81		"The type of the result."
82	)]
83	#[document_parameters(
84		"The function to apply to each element's index and reference.",
85		"The structure to map over."
86	)]
87	#[document_returns("The mapped structure.")]
88	#[document_examples]
89	///
90	/// ```
91	/// use fp_library::{
92	/// 	brands::*,
93	/// 	functions::explicit::*,
94	/// 	types::*,
95	/// };
96	///
97	/// let lazy = RcLazy::new(|| 42);
98	/// let mapped =
99	/// 	map_with_index::<LazyBrand<RcLazyConfig>, _, _, _, _>(|_, x: &i32| x.to_string(), &lazy);
100	/// assert_eq!(*mapped.evaluate(), "42");
101	/// ```
102	pub fn ref_map_with_index<'a, Brand: RefFunctorWithIndex, A: 'a, B: 'a>(
103		f: impl Fn(Brand::Index, &A) -> B + 'a,
104		fa: &Brand::Of<'a, A>,
105	) -> Brand::Of<'a, B> {
106		Brand::ref_map_with_index(f, fa)
107	}
108}
109
110pub use inner::*;