rust2fun/
and_then.rs

1//! AndThen.
2
3use core::marker::PhantomData;
4
5use crate::higher::Higher;
6
7/// Gives access to the [and_then] method. This trait is needed to implement [ApN]. The motivation
8/// for not using [FlatMap] is that there are situations where `and_then` can be implemented but
9/// not [FlatMap::flat_map], e.g. [Validated].
10///
11/// [and_then]: AndThen::and_then
12/// [ApN]: crate::ap_n::ApN
13/// [Validated]: crate::data::validated::Validated
14pub trait AndThen<B>: Higher {
15    /// Maps a function over a value in the context and flattens the resulting nested context.
16    fn and_then<F>(self, f: F) -> Self::Target<B>
17    where
18        F: FnMut(Self::Param) -> Self::Target<B>;
19}
20
21// TODO. Refactor this when specialization is stable.
22/// Macro to implement [AndThen] for types implementing a [FlatMap::flat_map].
23#[macro_export]
24macro_rules! and_then_flat_map {
25    ($name:ident<$( $t:tt ),+>) => {
26        impl<B, $( $t ),+> $crate::and_then::AndThen<B> for $name<$( $t ),+> {
27            #[inline]
28            fn and_then<F>(self, f: F) -> Self::Target<B>
29            where
30                F: FnMut(Self::Param) -> Self::Target<B>,
31            {
32                $crate::flatmap::FlatMap::flat_map(self, f)
33            }
34        }
35    };
36    ($name:ident<$( $t:tt ),+>, $ct:tt $(+ $dt:tt )*) => {
37        impl<B:$ct $(+ $dt )*, $( $t ),+> $crate::and_then::AndThen<B> for $name<$( $t ),+> {
38            #[inline]
39            fn and_then<F>(self, f: F) -> Self::Target<B>
40            where
41                F: FnMut(Self::Param) -> Self::Target<B>,
42            {
43                $crate::flatmap::FlatMap::flat_map(self, f)
44            }
45        }
46    };
47}
48
49impl<A, B> AndThen<B> for PhantomData<A> {
50    fn and_then<F>(self, _f: F) -> PhantomData<B>
51    where
52        F: FnMut(A) -> PhantomData<B>,
53    {
54        PhantomData
55    }
56}
57
58and_then_flat_map!(Option<T>);
59and_then_flat_map!(Result<T, E>);
60
61if_std! {
62    use std::boxed::Box;
63    use std::collections::*;
64    use std::hash::Hash;
65    use std::vec::Vec;
66    use crate::flatmap::FlatMap;
67
68    and_then_flat_map!(Vec<T>);
69    and_then_flat_map!(LinkedList<T>);
70    and_then_flat_map!(VecDeque<T>);
71    and_then_flat_map!(Box<T>);
72    and_then_flat_map!(BinaryHeap<T>, Ord);
73    and_then_flat_map!(BTreeSet<T>, Ord);
74    and_then_flat_map!(HashSet<T>, Hash + Eq);
75
76    impl<A, B, K: Hash + Eq> AndThen<B> for HashMap<K, A> {
77        #[inline]
78        fn and_then<F>(self, f: F) -> HashMap<K, B>
79        where
80            F: FnMut(A) -> HashMap<K, B>,
81        {
82            self.flat_map(f)
83        }
84    }
85}