hlist2/ops/map/map.rs
1#![allow(clippy::module_inception)]
2
3use crate::{Cons, HList, Nil};
4
5use super::{MapFn, Mapper};
6
7/// Transform one heterogenous list into another.
8pub trait Map<Mapper>: HList {
9 /// Type of new heterogenous list after transformation.
10 type Output: HList;
11
12 /// Transforms the heterogenous list into another heterogenous list
13 /// by applying an operation to each element by mapper.
14 ///
15 /// # Examples
16 ///
17 /// You can map the list if it is homogenous (all elements have the same type):
18 ///
19 /// ```
20 /// use hlist2::{hlist, ops::Map};
21 ///
22 /// let list = hlist![1, 2, 3];
23 /// assert_eq!(list.map(|x| 2 * x), hlist![2, 4, 6]);
24 /// ```
25 ///
26 /// Mapping of heterogenous list is possible with heterogenous list of closures as folder:
27 ///
28 /// ```
29 /// use hlist2::{hlist, ops::Map};
30 ///
31 /// let list = hlist![1, 2.0, true];
32 /// let list = list.map(
33 /// hlist![
34 /// |i| i + 2,
35 /// |f| f - 2.0,
36 /// |b: bool| !b,
37 /// ]
38 /// );
39 /// assert_eq!(list, hlist![3, 0.0, false]);
40 /// ```
41 ///
42 /// Or with special implementation of [mapper function](MapFn):
43 ///
44 /// ```
45 /// use hlist2::{
46 /// hlist,
47 /// ops::{Map, MapFn, Mapper},
48 /// };
49 ///
50 /// struct MyMapFn;
51 ///
52 /// impl MapFn<i32> for MyMapFn {
53 /// type Output = i32;
54 /// fn map(&mut self, n: i32) -> i32 { n + 3 }
55 /// }
56 /// impl MapFn<f32> for MyMapFn {
57 /// type Output = f32;
58 /// fn map(&mut self, f: f32) -> f32 { f + 8959.0 }
59 /// }
60 /// impl MapFn<bool> for MyMapFn {
61 /// type Output = bool;
62 /// fn map(&mut self, b: bool) -> bool { !b }
63 /// }
64 ///
65 /// let list = hlist![1, false, 42f32];
66 /// let list = list.map(Mapper(MyMapFn));
67 /// assert_eq!(list, hlist![4, true, 9001.0]);
68 /// ```
69 fn map(self, mapper: Mapper) -> Self::Output;
70}
71
72impl<M> Map<M> for Nil {
73 type Output = Nil;
74
75 fn map(self, _: M) -> Self::Output {
76 self
77 }
78}
79
80impl<M, R, Head, Tail> Map<M> for Cons<Head, Tail>
81where
82 M: FnMut(Head) -> R,
83 Tail: Map<M>,
84{
85 type Output = Cons<R, Tail::Output>;
86
87 fn map(self, mut mapper: M) -> Self::Output {
88 let Cons(head, tail) = self;
89 let head = mapper(head);
90 let tail = tail.map(mapper);
91 Cons(head, tail)
92 }
93}
94
95impl<MHead, MTail, Head, Tail, R> Map<Cons<MHead, MTail>> for Cons<Head, Tail>
96where
97 MHead: FnOnce(Head) -> R,
98 Tail: Map<MTail>,
99{
100 type Output = Cons<R, Tail::Output>;
101
102 fn map(self, mapper: Cons<MHead, MTail>) -> Self::Output {
103 let Cons(head, tail) = self;
104 let Cons(mapper_head, mapper_tail) = mapper;
105 let head = mapper_head(head);
106 let tail = tail.map(mapper_tail);
107 Cons(head, tail)
108 }
109}
110
111impl<M, Head, Tail> Map<Mapper<M>> for Cons<Head, Tail>
112where
113 M: MapFn<Head>,
114 Tail: Map<Mapper<M>>,
115{
116 type Output = Cons<M::Output, Tail::Output>;
117
118 fn map(self, mut mapper: Mapper<M>) -> Self::Output {
119 let Cons(head, tail) = self;
120 let head = mapper.map(head);
121 let tail = tail.map(mapper);
122 Cons(head, tail)
123 }
124}