Skip to main content

camel_api/
filter.rs

1use crate::exchange::Exchange;
2use std::sync::Arc;
3
4/// Predicate that determines whether an exchange passes the filter.
5/// Returns `true` to forward the exchange into the filter body; `false` to skip it.
6///
7/// This is a newtype around `Arc<dyn Fn(&Exchange) -> bool + Send + Sync>` so that
8/// it can implement `Debug` (used by `#[derive(Debug)]` on `BuilderStep` and friends).
9/// The `Deref` impl keeps the call-site ergonomic: `predicate(&exchange)` still works
10/// because `FilterPredicate` derefs to the inner `dyn Fn`.
11///
12/// Pre-v1.0: this used to be a type alias. Converted to a newtype (H2) so the
13/// containing structs (`WhenStep`, etc.) can be `#[derive(Debug)]`.
14pub struct FilterPredicate(pub Arc<dyn Fn(&Exchange) -> bool + Send + Sync>);
15
16impl FilterPredicate {
17    /// Create a new `FilterPredicate` from a closure or function pointer.
18    pub fn new<F>(f: F) -> Self
19    where
20        F: Fn(&Exchange) -> bool + Send + Sync + 'static,
21    {
22        FilterPredicate(Arc::new(f))
23    }
24}
25
26impl Clone for FilterPredicate {
27    fn clone(&self) -> Self {
28        FilterPredicate(Arc::clone(&self.0))
29    }
30}
31
32impl std::fmt::Debug for FilterPredicate {
33    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34        f.write_str("FilterPredicate(..)")
35    }
36}
37
38impl std::ops::Deref for FilterPredicate {
39    type Target = dyn Fn(&Exchange) -> bool + Send + Sync;
40
41    fn deref(&self) -> &Self::Target {
42        &*self.0
43    }
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49    use crate::{Exchange, Message};
50
51    #[test]
52    fn test_filter_predicate_is_callable() {
53        let pred = FilterPredicate::new(|ex: &Exchange| ex.input.body.as_text().is_some());
54        let ex = Exchange::new(Message::new("hello"));
55        assert!(pred(&ex));
56    }
57
58    #[test]
59    fn test_filter_predicate_debug_is_redacted() {
60        let pred = FilterPredicate::new(|_: &Exchange| true);
61        assert_eq!(format!("{pred:?}"), "FilterPredicate(..)");
62    }
63
64    #[test]
65    fn test_filter_predicate_clone_shares_arc() {
66        let pred = FilterPredicate::new(|_: &Exchange| true);
67        let cloned = pred.clone();
68        assert!(matches!(cloned, FilterPredicate(_)));
69    }
70}