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
/// List of filters that can be used to filter down results from a /// [Storkable](crate::Storkable). Once constructed, these can be /// attached using [Storkable::with_filters](crate::Storkable::with_filters). #[derive(Debug)] pub struct FilterSet<T> { filters: Option<Vec<Box<dyn Filter<T>>>>, } impl<T> FilterSet<T> { /// Filter results by a given predicate. pub fn add_filter<F: Filter<T> + 'static>(mut self, filter: F) -> Self { if self.filters.is_none() { self.filters = Some(Vec::new()); } // unwrap can't panic here because we filled the value above self.filters.as_mut().unwrap().push(Box::new(filter)); self } /// Check if this `Filters` matches the given `link`. pub(crate) fn matches(&self, val: &T) -> bool { if let Some(filters) = &self.filters { for filter in filters.iter() { if !filter.matches(&val) { return false; } } } true } } impl<T> Default for FilterSet<T> { /// Creates an empty filter set. fn default() -> Self { FilterSet { filters: None } } } /// We need to manually implement [Clone] for this struct because /// otherwise it won't be derived on values where T doesn't implement /// Clone (which would be an unnecessary restriction on our API as T /// is a type param on a method). impl<T> Clone for FilterSet<T> { fn clone(&self) -> Self { Self { filters: self.filters.clone(), } } } /// Predicate for any values of <T> passing through a /// [Storkable](crate::Storkable). See [html_filters] for example /// implementations. /// /// Note: *all* implementations of `Filter` should have an impl of /// [Clone] so they can be passed to children and modified without /// modifying FilterSets on parents. /// /// [html_filters]: (../stork_html/filters) pub trait Filter<T>: std::fmt::Debug + dyn_clone::DynClone { fn matches(&self, val: &T) -> bool; } /// we need to use dyn_clone's impl of cloning a boxed dynamically /// dispatched trait because implementing it involves a bit of unsafe /// code with recent changes to the compiler, so we'll trust them to /// handle it. impl<T> std::clone::Clone for Box<dyn Filter<T>> { fn clone(&self) -> Self { dyn_clone::clone_box(self.as_ref()) } } #[derive(Debug, Clone)] pub enum FilterType { StartsWith, EndsWith, Contains, Equals }