1use crate::{Bitmap, FieldName, FieldValuePair, FileIndex};
2use std::hash::{Hash, Hasher};
3use std::sync::Arc;
4
5#[derive(Clone, Debug, PartialEq, Eq, Hash)]
11#[cfg_attr(feature = "allocative", derive(allocative::Allocative))]
12enum FilterTarget {
13 Field(FieldName),
15 Pair(FieldValuePair),
17}
18
19#[derive(Clone, Debug)]
27#[cfg_attr(feature = "allocative", derive(allocative::Allocative))]
28pub struct Filter {
29 inner: Arc<FilterExpr<FilterTarget>>,
30}
31
32impl Filter {
33 pub fn match_field_name(name: FieldName) -> Self {
35 Self {
36 inner: Arc::new(FilterExpr::Match(FilterTarget::Field(name))),
37 }
38 }
39
40 pub fn match_field_value_pair(pair: FieldValuePair) -> Self {
42 Self {
43 inner: Arc::new(FilterExpr::Match(FilterTarget::Pair(pair))),
44 }
45 }
46
47 pub fn and(filters: Vec<Self>) -> Self {
49 let inner_filters: Vec<FilterExpr<FilterTarget>> =
50 filters.into_iter().map(|f| (*f.inner).clone()).collect();
51
52 Self {
53 inner: Arc::new(FilterExpr::and(inner_filters)),
54 }
55 }
56
57 pub fn or(filters: Vec<Self>) -> Self {
59 let inner_filters: Vec<FilterExpr<FilterTarget>> =
60 filters.into_iter().map(|f| (*f.inner).clone()).collect();
61
62 Self {
63 inner: Arc::new(FilterExpr::or(inner_filters)),
64 }
65 }
66
67 pub fn none() -> Self {
69 Self {
70 inner: Arc::new(FilterExpr::None),
71 }
72 }
73
74 pub fn is_none(&self) -> bool {
76 matches!(self.inner.as_ref(), FilterExpr::None)
77 }
78
79 pub fn evaluate(&self, file_index: &FileIndex) -> Bitmap {
81 self.inner.resolve(file_index).evaluate()
82 }
83}
84
85impl PartialEq for Filter {
86 fn eq(&self, other: &Self) -> bool {
87 if Arc::ptr_eq(&self.inner, &other.inner) {
89 return true;
90 }
91
92 self.inner == other.inner
94 }
95}
96
97impl Eq for Filter {}
98
99impl std::hash::Hash for Filter {
100 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
101 self.inner.hash(state);
102 }
103}
104
105impl std::fmt::Display for Filter {
106 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107 write!(f, "{}", self.inner)
108 }
109}
110
111#[derive(Clone, Debug, PartialEq)]
112#[cfg_attr(feature = "allocative", derive(allocative::Allocative))]
113enum FilterExpr<T> {
114 None,
115 Match(T),
116 Conjunction(Vec<Self>),
117 Disjunction(Vec<Self>),
118}
119
120impl Eq for FilterExpr<FilterTarget> {}
121
122impl Hash for FilterExpr<FilterTarget> {
123 fn hash<H: Hasher>(&self, state: &mut H) {
124 std::mem::discriminant(self).hash(state);
125
126 match self {
127 FilterExpr::None => {}
128 FilterExpr::Match(target) => target.hash(state),
129 FilterExpr::Conjunction(filters) => filters.hash(state),
130 FilterExpr::Disjunction(filters) => filters.hash(state),
131 }
132 }
133}
134
135impl FilterExpr<FilterTarget> {
136 fn and(filters: Vec<Self>) -> Self {
137 let mut flattened = Vec::new();
139 for filter in filters {
140 match filter {
141 FilterExpr::Conjunction(inner) => flattened.extend(inner),
142 FilterExpr::None => continue,
143 other => flattened.push(other),
144 }
145 }
146
147 match flattened.len() {
148 0 => FilterExpr::None,
149 1 => flattened.into_iter().next().unwrap(),
150 _ => FilterExpr::Conjunction(flattened),
151 }
152 }
153
154 fn or(filters: Vec<Self>) -> Self {
155 let mut flattened = Vec::new();
157 for filter in filters {
158 match filter {
159 FilterExpr::Disjunction(inner) => flattened.extend(inner),
160 FilterExpr::None => continue,
161 other => flattened.push(other),
162 }
163 }
164
165 match flattened.len() {
166 0 => FilterExpr::None,
167 1 => flattened.into_iter().next().unwrap(),
168 _ => FilterExpr::Disjunction(flattened),
169 }
170 }
171
172 fn resolve(&self, file_index: &FileIndex) -> FilterExpr<Bitmap> {
174 match self {
175 FilterExpr::None => FilterExpr::None,
176 FilterExpr::Match(target) => match target {
177 FilterTarget::Field(field_name) => {
178 let matches: Vec<_> = file_index
180 .bitmaps()
181 .iter()
182 .filter(|(pair, _)| pair.field() == field_name.as_str())
183 .map(|(_, bitmap)| FilterExpr::Match(bitmap.clone()))
184 .collect();
185
186 match matches.len() {
187 0 => FilterExpr::None,
188 1 => matches.into_iter().next().unwrap(),
189 _ => FilterExpr::Disjunction(matches),
190 }
191 }
192 FilterTarget::Pair(pair) => {
193 if let Some(bitmap) = file_index.bitmaps().get(pair) {
195 FilterExpr::Match(bitmap.clone())
196 } else {
197 FilterExpr::None
198 }
199 }
200 },
201 FilterExpr::Conjunction(filters) => {
202 let mut resolved = Vec::with_capacity(filters.len());
203 for filter in filters {
204 let r = filter.resolve(file_index);
205 if matches!(r, FilterExpr::None) {
206 return FilterExpr::None;
207 }
208 resolved.push(r);
209 }
210
211 match resolved.len() {
212 0 => FilterExpr::None,
213 1 => resolved.into_iter().next().unwrap(),
214 _ => FilterExpr::Conjunction(resolved),
215 }
216 }
217 FilterExpr::Disjunction(filters) => {
218 let mut resolved = Vec::with_capacity(filters.len());
219 for filter in filters {
220 let r = filter.resolve(file_index);
221 if !matches!(r, FilterExpr::None) {
222 resolved.push(r);
223 }
224 }
225
226 match resolved.len() {
227 0 => FilterExpr::None,
228 1 => resolved.into_iter().next().unwrap(),
229 _ => FilterExpr::Disjunction(resolved),
230 }
231 }
232 }
233 }
234}
235
236impl std::fmt::Display for FilterExpr<FilterTarget> {
237 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
238 match self {
239 FilterExpr::None => write!(f, "None"),
240 FilterExpr::Match(target) => write_filter_target(f, target),
241 FilterExpr::Conjunction(filters) => write_filter_list(f, filters, " AND "),
242 FilterExpr::Disjunction(filters) => write_filter_list(f, filters, " OR "),
243 }
244 }
245}
246
247fn write_filter_target(f: &mut std::fmt::Formatter<'_>, target: &FilterTarget) -> std::fmt::Result {
248 match target {
249 FilterTarget::Field(name) => write!(f, "{}", name),
250 FilterTarget::Pair(pair) => write!(f, "{}", pair),
251 }
252}
253
254fn write_filter_list(
255 f: &mut std::fmt::Formatter<'_>,
256 filters: &[FilterExpr<FilterTarget>],
257 separator: &str,
258) -> std::fmt::Result {
259 write!(f, "(")?;
260 for (i, filter) in filters.iter().enumerate() {
261 if i > 0 {
262 write!(f, "{separator}")?;
263 }
264 write!(f, "{}", filter)?;
265 }
266 write!(f, ")")
267}
268
269impl FilterExpr<Bitmap> {
270 fn evaluate(&self) -> Bitmap {
272 match self {
273 Self::None => Bitmap::new(),
274 Self::Match(bitmap) => bitmap.clone(),
275 Self::Conjunction(filter_exprs) => {
276 if filter_exprs.is_empty() {
277 return Bitmap::new();
278 }
279
280 let mut result = filter_exprs[0].evaluate();
281 for expr in filter_exprs.iter().skip(1) {
282 result &= expr.evaluate();
283 if result.is_empty() {
284 break; }
286 }
287 result
288 }
289 Self::Disjunction(filter_exprs) => {
290 let mut result = Bitmap::new();
291 for expr in filter_exprs.iter() {
292 result |= expr.evaluate();
293 }
294 result
295 }
296 }
297 }
298}