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 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
use crate :: { import::* }; /// Predicate for filtering events. This is an enum because closures that capture variables from /// their environment need to be boxed. More often than not, an event will be a simple enum and /// the predicate will just match on the variant, so it would be wasteful to impose boxing in those /// cases, hence there is a function pointer variant which does not require boxing. This should /// be preferred where possible. /// /// ``` /// use pharos::*; /// /// let a = 5; /// /// // This closure captures the a variable from it's environment. /// // We can still use it as a filter by boxing it with `closure`. /// // /// // Note: it depends on the circumstances, but often enough, we need to /// // annotate the type of the event parameter to the predicate. /// // /// // For this example we use bool as event type for simplicity, but it works /// // just the same if that's an enum. /// // /// let predicate = move |_: &bool| { a; true }; /// /// let filter = Filter::<bool>::closure( predicate ); /// /// // This one does not capture anything, so it can be stored as a function pointer /// // without boxing. /// // /// let predicate = move |_: &bool| { true }; /// /// let filter = Filter::<bool>::pointer( predicate ); /// /// // You can also use actual functions as filters. /// // /// fn predicate_function( event: &bool ) -> bool { true } /// /// let filter = Filter::<bool>::pointer( predicate_function ); /// ``` // pub enum Filter<Event> where Event: Clone + 'static + Send , { /// A function pointer to use to filter events. // Pointer( fn(&Event) -> bool ), /// A boxed closure to use to filter events. // Closure( Box<dyn FnMut(&Event) -> bool + Send> ), } impl<Event> Filter<Event> where Event: Clone + 'static + Send { /// Construct a filter from a closure that captures something from it's environment. This will /// be boxed and stored under the [Filter::Closure] variant. To avoid boxing, do not capture /// any variables from the environment and use [Filter::pointer]. // pub fn closure<F>( predicate: F ) -> Self where F: FnMut(&Event) -> bool + Send + 'static { Self::Closure( Box::new( predicate ) ) } /// Construct a filter from a function pointer to a predicate. // pub fn pointer( predicate: fn(&Event) -> bool ) -> Self { Self::Pointer( predicate ) } /// Invoke the predicate // pub(crate) fn call( &mut self, evt: &Event ) -> bool { match self { Self::Pointer(f) => f(evt), Self::Closure(f) => f(evt), } } } impl<Event> fmt::Debug for Filter<Event> where Event: Clone + 'static + Send { fn fmt( &self, f: &mut fmt::Formatter<'_> ) -> fmt::Result { match self { Self::Pointer(_) => write!( f, "pharos::Filter<{}>::Pointer(_)", type_name::<Event>() ), Self::Closure(_) => write!( f, "pharos::Filter<{}>::Closure(_)", type_name::<Event>() ), } } } #[ cfg( test ) ] // mod tests { use super::*; #[test] // fn pointer() { let f = Filter::pointer( |b| *b ); assert_matches!( f, Filter::Pointer(_) ); } #[test] // fn closure() { let f = Filter::closure( |b| *b ); assert_matches!( f, Filter::Closure(_) ); } #[test] // fn debug() { let f = Filter::pointer( |b| *b ); let g = Filter::closure( |b| *b ); assert_eq!( "pharos::Filter<bool>::Pointer(_)", &format!( "{:?}", f ) ); assert_eq!( "pharos::Filter<bool>::Closure(_)", &format!( "{:?}", g ) ); } }