watchexec/
filter.rs

1//! The `Filterer` trait for event filtering.
2
3use std::{fmt, sync::Arc};
4
5use watchexec_events::{Event, Priority};
6
7use crate::{changeable::Changeable, error::RuntimeError};
8
9/// An interface for filtering events.
10pub trait Filterer: std::fmt::Debug + Send + Sync {
11	/// Called on (almost) every event, and should return `false` if the event is to be discarded.
12	///
13	/// Checking whether an event passes a filter is synchronous, should be fast, and must not block
14	/// the thread. Do any expensive stuff upfront during construction of your filterer, or in a
15	/// separate thread/task, as needed.
16	///
17	/// Returning an error will also fail the event processing, but the error will be propagated to
18	/// the watchexec error handler. While the type signature supports any [`RuntimeError`], it's
19	/// preferred that you create your own error type and return it wrapped in the
20	/// [`RuntimeError::Filterer`] variant with the name of your filterer as `kind`.
21	fn check_event(&self, event: &Event, priority: Priority) -> Result<bool, RuntimeError>;
22}
23
24impl Filterer for () {
25	fn check_event(&self, _event: &Event, _priority: Priority) -> Result<bool, RuntimeError> {
26		Ok(true)
27	}
28}
29
30impl<T: Filterer> Filterer for Arc<T> {
31	fn check_event(&self, event: &Event, priority: Priority) -> Result<bool, RuntimeError> {
32		Self::as_ref(self).check_event(event, priority)
33	}
34}
35
36/// A shareable `Filterer` that doesn't hold a lock when it is called.
37///
38/// This is a specialisation of [`Changeable`] for `Filterer`.
39pub struct ChangeableFilterer(Changeable<Arc<dyn Filterer>>);
40impl ChangeableFilterer {
41	/// Replace the filterer with a new one.
42	///
43	/// Panics if the lock was poisoned.
44	pub fn replace(&self, new: impl Filterer + 'static) {
45		self.0.replace(Arc::new(new));
46	}
47}
48
49impl Filterer for ChangeableFilterer {
50	fn check_event(&self, event: &Event, priority: Priority) -> Result<bool, RuntimeError> {
51		Arc::as_ref(&self.0.get()).check_event(event, priority)
52	}
53}
54
55// the derive adds a T: Clone bound
56impl Clone for ChangeableFilterer {
57	fn clone(&self) -> Self {
58		Self(Changeable::clone(&self.0))
59	}
60}
61
62impl Default for ChangeableFilterer {
63	fn default() -> Self {
64		Self(Changeable::new(Arc::new(())))
65	}
66}
67
68impl fmt::Debug for ChangeableFilterer {
69	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70		f.debug_struct("ChangeableFilterer")
71			.field("filterer", &format!("{:?}", self.0.get()))
72			.finish_non_exhaustive()
73	}
74}