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::*;