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}