map_self/
lib.rs

1#![warn(clippy::pedantic)]
2
3/// Functions to transform a type itself instead of something it contains with the usual closure approach.
4pub trait MapSelf {
5    fn map_self<O, T>(self, op: O) -> T
6    where
7        O: FnOnce(Self) -> T,
8        Self: Sized,
9    {
10        #![must_use]
11        //! Example:
12        //!
13        //! ```ignore
14        //! let (hour, meridiem) = if use_12_hour_clock {
15        //!     self.hour_meridiem() // Yields 12-hour clock time.
16        //!         .map_self(|(hour, meridiem)| (hour, Some(meridiem)))
17        //! } else {
18        //!     (self.hour, None)
19        //! };
20        //! ```
21
22        op(self)
23    }
24
25    fn map_self_or_keep<O>(self, op: O) -> Self
26    where
27        O: FnOnce(&Self) -> Option<Self>,
28        Self: Sized,
29    {
30        #![must_use]
31        //! Example:
32        //!
33        //! ```ignore
34        //! // Initialize time to check for double-click.
35        //! let mut last_click_time = Instant::now()
36        //!     .map_self_or_keep(|now| now.checked_sub(Duration::from_secs(60)));
37        //! ```
38
39        op(&self).unwrap_or(self)
40    }
41}
42
43impl<T> MapSelf for T {}
44
45#[cfg(test)]
46mod tests {
47    use crate::MapSelf;
48
49    #[test]
50    fn map_self() {
51        assert_eq!(
52            (1, 2).map_self(|(first, second)| (first + 1, Some(second - 1))),
53            (2, Some(1))
54        );
55        assert_eq!((1, 2).map_self(|(first, second)| first + second), 3);
56    }
57
58    #[test]
59    fn map_self_or_keep() {
60        let only_positive: usize = 10;
61        assert_eq!(
62            only_positive.map_self_or_keep(|val| val.checked_sub(100)),
63            10
64        );
65        assert_eq!(only_positive.map_self_or_keep(|val| val.checked_sub(5)), 5);
66    }
67}