composable_indexes/index/
filtered.rs1use crate::{
2 ShallowClone,
3 core::{Index, Insert, Remove, Seal, Update},
4};
5
6pub 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}