composable_indexes/index/
filtered.rs

1use crate::{
2    ShallowClone,
3    core::{Index, Insert, Remove, Seal, Update},
4};
5
6/// Higher-order index that filters entries based on a predicate function.
7pub struct Filtered<In, Out, Inner> {
8    f: fn(&In) -> Option<Out>,
9    inner: Inner,
10}
11
12impl<In, Out, Inner> Clone for Filtered<In, Out, Inner>
13where
14    Inner: Clone,
15{
16    fn clone(&self) -> Self {
17        Filtered {
18            f: self.f,
19            inner: self.inner.clone(),
20        }
21    }
22}
23
24impl<In, Out, Inner: ShallowClone> ShallowClone for Filtered<In, Out, Inner> {}
25
26impl<In, Out, Inner> Filtered<In, Out, Inner> {
27    pub fn new(f: fn(&In) -> Option<Out>, inner: Inner) -> Self {
28        Filtered { f, inner }
29    }
30}
31
32impl<In, Out, Inner> Index<In> for Filtered<In, Out, Inner>
33where
34    Inner: Index<Out>,
35{
36    #[inline]
37    fn insert(&mut self, seal: Seal, op: &Insert<In>) {
38        if let Some(transformed) = (self.f)(op.new) {
39            self.inner.insert(
40                seal,
41                &Insert {
42                    key: op.key,
43                    new: &transformed,
44                },
45            );
46        }
47    }
48
49    #[inline]
50    fn update(&mut self, seal: Seal, op: &Update<In>) {
51        let new_opt = (self.f)(op.new);
52        let existing_opt = (self.f)(op.existing);
53
54        match (existing_opt, new_opt) {
55            (Some(existing), Some(new)) => {
56                self.inner.update(
57                    seal,
58                    &Update {
59                        key: op.key,
60                        new: &new,
61                        existing: &existing,
62                    },
63                );
64            }
65            (Some(existing), None) => {
66                self.inner.remove(
67                    seal,
68                    &Remove {
69                        key: op.key,
70                        existing: &existing,
71                    },
72                );
73            }
74            (None, Some(new)) => {
75                self.inner.insert(
76                    seal,
77                    &Insert {
78                        key: op.key,
79                        new: &new,
80                    },
81                );
82            }
83            (None, None) => {}
84        }
85    }
86
87    #[inline]
88    fn remove(&mut self, seal: Seal, op: &Remove<In>) {
89        if let Some(existing) = (self.f)(op.existing) {
90            self.inner.remove(
91                seal,
92                &Remove {
93                    key: op.key,
94                    existing: &existing,
95                },
96            );
97        }
98    }
99}
100
101impl<In, Out, Inner> Filtered<In, Out, Inner> {
102    pub fn inner(&self) -> &Inner {
103        &self.inner
104    }
105}
106
107impl<In, Out, Inner> core::ops::Deref for Filtered<In, Out, Inner> {
108    type Target = Inner;
109
110    fn deref(&self) -> &Self::Target {
111        &self.inner
112    }
113}
114
115#[cfg(test)]
116mod tests {
117    use super::*;
118    use crate::aggregation;
119    use crate::testutils::prop_assert_reference;
120
121    #[test]
122    fn test_reference() {
123        prop_assert_reference(
124            || {
125                Filtered::new(
126                    |b: &bool| if *b { Some(true) } else { None },
127                    aggregation::Count::new(),
128                )
129            },
130            |db| db.query(|ix| ix.inner().count()),
131            |xs| xs.iter().filter(|&&b| b).count(),
132            None,
133        );
134    }
135}