fp_library/dispatch/functor_with_index.rs
1//! Dispatch for [`FunctorWithIndex::map_with_index`](crate::classes::FunctorWithIndex::map_with_index) and
2//! [`RefFunctorWithIndex::ref_map_with_index`](crate::classes::RefFunctorWithIndex::ref_map_with_index).
3//!
4//! Provides the [`MapWithIndexDispatch`] trait and a unified [`explicit::map_with_index`] free function
5//! that routes to the appropriate trait method based on the closure's argument
6//! type.
7//!
8//! ### Examples
9//!
10//! ```
11//! use fp_library::{
12//! brands::*,
13//! functions::explicit::*,
14//! };
15//!
16//! // Owned: dispatches to FunctorWithIndex::map_with_index
17//! let y = map_with_index::<VecBrand, _, _, _, _>(|i, x: i32| x + i as i32, vec![10, 20, 30]);
18//! assert_eq!(y, vec![10, 21, 32]);
19//!
20//! // By-ref: dispatches to RefFunctorWithIndex::ref_map_with_index
21//! let v = vec![10, 20, 30];
22//! let y = map_with_index::<VecBrand, _, _, _, _>(|i, x: &i32| *x + i as i32, &v);
23//! assert_eq!(y, vec![10, 21, 32]);
24//! ```
25
26#[fp_macros::document_module]
27pub(crate) mod inner {
28 use {
29 crate::{
30 classes::{
31 FunctorWithIndex,
32 RefFunctorWithIndex,
33 WithIndex,
34 },
35 dispatch::{
36 Ref,
37 Val,
38 },
39 kinds::*,
40 },
41 fp_macros::*,
42 };
43
44 /// Trait that routes a map_with_index operation to the appropriate type class method.
45 ///
46 /// The `Marker` type parameter is an implementation detail resolved by
47 /// the compiler from the closure's argument type; callers never specify
48 /// it directly. The `FA` type parameter is inferred from the container
49 /// argument: owned for Val dispatch, borrowed for Ref dispatch.
50 #[document_type_parameters(
51 "The lifetime of the values.",
52 "The brand of the functor.",
53 "The type of the value(s) inside the functor.",
54 "The type of the result(s) of applying the function.",
55 "The container type (owned or borrowed), inferred from the argument.",
56 "Dispatch marker type, inferred automatically. Either [`Val`](crate::dispatch::Val) or [`Ref`](crate::dispatch::Ref)."
57 )]
58 #[document_parameters("The closure implementing this dispatch.")]
59 pub trait MapWithIndexDispatch<
60 'a,
61 Brand: Kind_cdc7cd43dac7585f + WithIndex,
62 A: 'a,
63 B: 'a,
64 FA,
65 Marker,
66 > {
67 /// Perform the dispatched map_with_index operation.
68 #[document_signature]
69 ///
70 #[document_parameters("The functor instance containing the value(s).")]
71 ///
72 #[document_returns(
73 "A new functor instance containing the result(s) of applying the function with index."
74 )]
75 #[document_examples]
76 ///
77 /// ```
78 /// use fp_library::{
79 /// brands::*,
80 /// functions::explicit::*,
81 /// };
82 ///
83 /// let result = map_with_index::<VecBrand, _, _, _, _>(|i, x: i32| x + i as i32, vec![10, 20, 30]);
84 /// assert_eq!(result, vec![10, 21, 32]);
85 /// ```
86 fn dispatch(
87 self,
88 fa: FA,
89 ) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>);
90 }
91
92 // -- Val: Fn(Brand::Index, A) -> B -> FunctorWithIndex::map_with_index --
93
94 /// Routes `Fn(Brand::Index, A) -> B` closures to [`FunctorWithIndex::map_with_index`].
95 #[document_type_parameters(
96 "The lifetime of the values.",
97 "The brand of the functor.",
98 "The type of the value(s) inside the functor.",
99 "The type of the result(s) of applying the function.",
100 "The closure type."
101 )]
102 #[document_parameters("The closure that takes an index and owned values.")]
103 impl<'a, Brand, A, B, F>
104 MapWithIndexDispatch<
105 'a,
106 Brand,
107 A,
108 B,
109 Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
110 Val,
111 > for F
112 where
113 Brand: FunctorWithIndex,
114 A: 'a,
115 B: 'a,
116 Brand::Index: 'a,
117 F: Fn(Brand::Index, A) -> B + 'a,
118 {
119 #[document_signature]
120 ///
121 #[document_parameters("The functor instance containing the value(s).")]
122 ///
123 #[document_returns(
124 "A new functor instance containing the result(s) of applying the function with index."
125 )]
126 #[document_examples]
127 ///
128 /// ```
129 /// use fp_library::{
130 /// brands::*,
131 /// functions::explicit::*,
132 /// };
133 ///
134 /// let result = map_with_index::<VecBrand, _, _, _, _>(|i, x: i32| x + i as i32, vec![10, 20, 30]);
135 /// assert_eq!(result, vec![10, 21, 32]);
136 /// ```
137 fn dispatch(
138 self,
139 fa: Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
140 ) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
141 Brand::map_with_index(self, fa)
142 }
143 }
144
145 // -- Ref: Fn(Brand::Index, &A) -> B -> RefFunctorWithIndex::ref_map_with_index --
146
147 /// Routes `Fn(Brand::Index, &A) -> B` closures to [`RefFunctorWithIndex::ref_map_with_index`].
148 ///
149 /// The container must be passed by reference (`&fa`).
150 #[document_type_parameters(
151 "The lifetime of the values.",
152 "The borrow lifetime.",
153 "The brand of the functor.",
154 "The type of the value(s) inside the functor.",
155 "The type of the result(s) of applying the function.",
156 "The closure type."
157 )]
158 #[document_parameters("The closure that takes an index and references.")]
159 impl<'a, 'b, Brand, A, B, F>
160 MapWithIndexDispatch<
161 'a,
162 Brand,
163 A,
164 B,
165 &'b Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
166 Ref,
167 > for F
168 where
169 Brand: RefFunctorWithIndex,
170 A: 'a,
171 B: 'a,
172 Brand::Index: 'a,
173 F: Fn(Brand::Index, &A) -> B + 'a,
174 {
175 #[document_signature]
176 ///
177 #[document_parameters("A reference to the functor instance.")]
178 ///
179 #[document_returns(
180 "A new functor instance containing the result(s) of applying the function with index."
181 )]
182 #[document_examples]
183 ///
184 /// ```
185 /// use fp_library::{
186 /// brands::*,
187 /// functions::explicit::*,
188 /// };
189 ///
190 /// let v = vec![10, 20, 30];
191 /// let result = map_with_index::<VecBrand, _, _, _, _>(|i, x: &i32| *x + i as i32, &v);
192 /// assert_eq!(result, vec![10, 21, 32]);
193 /// ```
194 fn dispatch(
195 self,
196 fa: &'b Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
197 ) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
198 Brand::ref_map_with_index(self, fa)
199 }
200 }
201
202 // -- Inference wrapper --
203
204 /// Maps a function with index over a functor, inferring the brand from the container type.
205 ///
206 /// The `Brand` type parameter is inferred from the concrete type of `fa`
207 /// via [`InferableBrand`](crate::kinds::InferableBrand_cdc7cd43dac7585f). Both owned and borrowed containers are supported.
208 ///
209 /// For types with multiple brands, use
210 /// [`explicit::map_with_index`](crate::functions::explicit::map_with_index) with a turbofish.
211 #[document_signature]
212 ///
213 #[document_type_parameters(
214 "The lifetime of the values.",
215 "The container type (owned or borrowed). Brand is inferred from this.",
216 "The type of the value(s) inside the functor.",
217 "The type of the result(s) of applying the function.",
218 "Dispatch marker type, inferred automatically."
219 )]
220 ///
221 #[document_parameters(
222 "The function to apply to each value and its index.",
223 "The functor instance (owned or borrowed)."
224 )]
225 ///
226 #[document_returns("A new functor instance containing the results.")]
227 #[document_examples]
228 ///
229 /// ```
230 /// use fp_library::functions::*;
231 ///
232 /// let y = map_with_index(|i, x: i32| x + i as i32, vec![10, 20, 30]);
233 /// assert_eq!(y, vec![10, 21, 32]);
234 /// ```
235 pub fn map_with_index<'a, FA, A: 'a, B: 'a, Marker>(
236 f: impl MapWithIndexDispatch<
237 'a,
238 <FA as InferableBrand_cdc7cd43dac7585f>::Brand,
239 A,
240 B,
241 FA,
242 Marker,
243 >,
244 fa: FA,
245 ) -> Apply!(<<FA as InferableBrand!(type Of<'a, A: 'a>: 'a;)>::Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)
246 where
247 FA: InferableBrand_cdc7cd43dac7585f,
248 <FA as InferableBrand_cdc7cd43dac7585f>::Brand: WithIndex, {
249 f.dispatch(fa)
250 }
251
252 // -- Explicit dispatch free function --
253
254 /// Explicit dispatch functions requiring a Brand turbofish.
255 ///
256 /// For most use cases, prefer the inference-enabled wrappers from
257 /// [`functions`](crate::functions).
258 pub mod explicit {
259 use super::*;
260
261 /// Maps a function with index over the values in a functor context.
262 ///
263 /// Dispatches to either [`FunctorWithIndex::map_with_index`] or
264 /// [`RefFunctorWithIndex::ref_map_with_index`] based on the closure's argument type:
265 ///
266 /// - If the closure takes owned values (`Fn(Index, A) -> B`) and the container is
267 /// owned, dispatches to [`FunctorWithIndex::map_with_index`].
268 /// - If the closure takes references (`Fn(Index, &A) -> B`) and the container is
269 /// borrowed (`&fa`), dispatches to [`RefFunctorWithIndex::ref_map_with_index`].
270 ///
271 /// The `Marker` and `FA` type parameters are inferred automatically by the
272 /// compiler from the closure's argument type and the container argument.
273 /// Callers write `map_with_index::<Brand, _, _, _, _>(...)` and never need to
274 /// specify `Marker` or `FA` explicitly.
275 ///
276 /// The dispatch is resolved at compile time with no runtime cost.
277 #[document_signature]
278 ///
279 #[document_type_parameters(
280 "The lifetime of the values.",
281 "The brand of the functor.",
282 "The type of the value(s) inside the functor.",
283 "The type of the result(s) of applying the function.",
284 "The container type (owned or borrowed), inferred from the argument.",
285 "Dispatch marker type, inferred automatically."
286 )]
287 ///
288 #[document_parameters(
289 "The function to apply to each value and its index.",
290 "The functor instance (owned for Val, borrowed for Ref)."
291 )]
292 ///
293 #[document_returns(
294 "A new functor instance containing the result(s) of applying the function with index."
295 )]
296 ///
297 #[document_examples]
298 ///
299 /// ```
300 /// use fp_library::{
301 /// brands::*,
302 /// functions::explicit::*,
303 /// };
304 ///
305 /// // Owned: dispatches to FunctorWithIndex::map_with_index
306 /// let y = map_with_index::<VecBrand, _, _, _, _>(|i, x: i32| x + i as i32, vec![10, 20, 30]);
307 /// assert_eq!(y, vec![10, 21, 32]);
308 ///
309 /// // By-ref: dispatches to RefFunctorWithIndex::ref_map_with_index
310 /// let v = vec![10, 20, 30];
311 /// let y = map_with_index::<VecBrand, _, _, _, _>(|i, x: &i32| *x + i as i32, &v);
312 /// assert_eq!(y, vec![10, 21, 32]);
313 /// ```
314 pub fn map_with_index<
315 'a,
316 Brand: Kind_cdc7cd43dac7585f + WithIndex,
317 A: 'a,
318 B: 'a,
319 FA,
320 Marker,
321 >(
322 f: impl MapWithIndexDispatch<'a, Brand, A, B, FA, Marker>,
323 fa: FA,
324 ) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
325 f.dispatch(fa)
326 }
327 }
328}
329
330pub use inner::*;