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 ) );
	}
}