summaryrefslogtreecommitdiffstats
path: root/src/impl_traits.rs
blob: 03e616e17d39d7b379f699acde13a2d45f3eeea4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//

/// Creates operator implementations for a Filter struct
/// Currently only Fn and Filter implementations are handled
///
/// Takes at least two arguments: the struct to implement the traits for, and
/// the block to define the filter function. Preceeding the block should be the
/// variables for self and the passed in argument to filter, separated by spaces.
/// After that, any filter generics needed for the struct should be specified.
///
/// # Examples
///
/// ```
/// # #![cfg_attr(feature = "unstable-filter-as-fn", feature(unboxed_closures, fn_traits))]
/// # #[macro_use] extern crate filters;
/// # use filters::filter::Filter;
/// # fn main() {
/// struct Or<T, U> {
///     a: T,
///     b: U
/// }
///
/// impl_operators!(Or, self e { self.a.filter(e) || self.b.filter(e) }, T, U);
///
/// let or = Or {a: |&x: &i32| x < 5, b: |&x: &i32| x > 10};
/// assert_eq!(or.filter(&0), true);
/// assert_eq!(or.filter(&7), false);
/// assert_eq!(or.filter(&15), true);
/// // If unstable-filter-as-fn is enabled `or` will also be a Fn(&i32) -> bool
/// # }
/// ```
#[macro_export]
macro_rules! impl_operators {
    ($struct_ident:ident, $self_var: ident $arg_var: ident $filter_impl:block, $( $generic:ident ),*) => {
        #[cfg(feature = "unstable-filter-as-fn")]
        impl<'a, I, $( $generic: Filter<I>, )*> FnOnce<(&'a I,)> for $struct_ident<$( $generic, )*> {
            type Output = bool;
            extern "rust-call" fn call_once<'b>(self, (arg,): (&'a I,)) -> Self::Output {
                self.filter(arg)
            }
        }

        #[cfg(feature = "unstable-filter-as-fn")]
        impl<'a, I, $( $generic: Filter<I>, )*> FnMut<(&'a I,)> for $struct_ident<$( $generic, )*> {
            extern "rust-call" fn call_mut<'b>(&mut self, (arg,): (&'a I,)) -> Self::Output {
                self.filter(arg)
            }
        }

        #[cfg(feature = "unstable-filter-as-fn")]
        impl<'a, I, $( $generic: Filter<I>, )*> Fn<(&'a I,)> for $struct_ident<$( $generic, )*> {
            #[allow(unused_variables)]
            extern "rust-call" fn call<'b>(&$self_var, ($arg_var,): (&'a I,)) -> Self::Output $filter_impl
        }

        #[cfg(not(feature = "unstable-filter-as-fn"))]
        impl<I, $( $generic: Filter<I>, )*> Filter<I> for $struct_ident<$( $generic, )*> {
            #[allow(unused_variables)]
            fn filter(&$self_var, $arg_var: &I) -> bool $filter_impl
        }
    };
    ($struct_ident:ident, $self_var: ident $arg_var: ident $filter_impl: block) => {
        impl_operators!($struct_ident, $self_var $arg_var $filter_impl, );
    };
}

/// Variant of impl_operators!() macro for FailableFilter types
#[macro_export]
macro_rules! impl_failable_operators {
    ($struct_ident:ident, $self_var: ident $arg_var: ident $filter_impl:block, $( $generic:ident ),*) => {
        #[cfg(feature = "unstable-filter-as-fn")]
        impl<'a, I, $( $generic: Filter<I>, )*> FnOnce<(&'a I,)> for $struct_ident<$( $generic, )*> {
            type Output = Result<bool, Error>;
            extern "rust-call" fn call_once<'b>(self, (arg,): (&'a I,)) -> Self::Output {
                self.filter(arg)
            }
        }

        #[cfg(feature = "unstable-filter-as-fn")]
        impl<'a, I, $( $generic: Filter<I>, )*> FnMut<(&'a I,)> for $struct_ident<$( $generic, )*> {
            extern "rust-call" fn call_mut<'b>(&mut self, (arg,): (&'a I,)) -> Self::Output {
                self.filter(arg)
            }
        }

        #[cfg(feature = "unstable-filter-as-fn")]
        impl<'a, I, $( $generic: Filter<I>, )*> Fn<(&'a I,)> for $struct_ident<$( $generic, )*> {
            #[allow(unused_variables)]
            extern "rust-call" fn call<'b>(&$self_var, ($arg_var,): (&'a I,)) -> Self::Output $filter_impl
        }

        #[cfg(not(feature = "unstable-filter-as-fn"))]
        impl<I, $( $generic: FailableFilter<I>, )*> FailableFilter<I> for $struct_ident<$( $generic, )*> {
            #[allow(unused_variables)]
            fn filter(&$self_var, $arg_var: &I) -> Result<bool, Error> $filter_impl
        }
    };
    ($struct_ident:ident, $self_var: ident $arg_var: ident $filter_impl: block) => {
        impl_operators!($struct_ident, $self_var $arg_var $filter_impl, );
    };
}