1use std::fmt;
11
12use crate::Condition;
13use crate::FilterExpressionBuilder;
14use crate::FilterExpressionView;
15use crate::FilterLimitKind;
16use crate::FilterLimits;
17use crate::FilterMatchOptions;
18use crate::Metadata;
19use crate::MetadataError;
20use crate::MetadataResult;
21use crate::filter::internal::FilterExpressionNode;
22use crate::filter::internal::MatchOutcome;
23
24#[derive(Clone, PartialEq)]
50#[must_use]
51pub struct FilterExpression {
52 node: FilterExpressionNode,
54 node_count: usize,
56 max_depth: usize,
58}
59
60impl fmt::Debug for FilterExpression {
61 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
64 formatter
65 .debug_struct("FilterExpression")
66 .field("node", &self.node)
67 .finish()
68 }
69}
70
71impl FilterExpression {
72 #[inline(always)]
74 #[must_use]
75 pub const fn builder() -> FilterExpressionBuilder {
76 FilterExpressionBuilder::new()
77 }
78
79 #[inline(always)]
81 #[must_use = "the constructed all-matching expression should be used"]
82 pub const fn match_all() -> Self {
83 Self::true_expression()
84 }
85
86 #[inline(always)]
88 #[must_use = "the constructed no-match expression should be used"]
89 pub const fn match_none() -> Self {
90 Self::false_expression()
91 }
92
93 #[inline]
100 pub fn try_and(self, other: Self) -> MetadataResult<Self> {
101 let expression = Self::and_unchecked(self, other);
102 expression.validate_limits(FilterLimits::MAX)?;
103 Ok(expression)
104 }
105
106 #[inline]
113 pub fn try_or(self, other: Self) -> MetadataResult<Self> {
114 let expression = Self::or_unchecked(self, other);
115 expression.validate_limits(FilterLimits::MAX)?;
116 Ok(expression)
117 }
118
119 #[inline]
126 pub fn try_not(self) -> MetadataResult<Self> {
127 let expression = self.negated_unchecked();
128 expression.validate_limits(FilterLimits::MAX)?;
129 Ok(expression)
130 }
131
132 #[inline(always)]
138 #[must_use = "the expression view should be inspected"]
139 pub fn view(&self) -> FilterExpressionView<'_> {
140 match &self.node {
141 FilterExpressionNode::Condition(condition) => FilterExpressionView::Condition(condition),
142 FilterExpressionNode::And(children) => FilterExpressionView::And(children),
143 FilterExpressionNode::Or(children) => FilterExpressionView::Or(children),
144 FilterExpressionNode::Not(inner) => FilterExpressionView::Not(inner),
145 FilterExpressionNode::True => FilterExpressionView::True,
146 FilterExpressionNode::False => FilterExpressionView::False,
147 }
148 }
149
150 #[inline]
160 pub(crate) fn condition(condition: Condition) -> MetadataResult<Self> {
161 condition.validate_operands()?;
162 Ok(Self {
163 node: FilterExpressionNode::Condition(condition),
164 node_count: 1,
165 max_depth: 1,
166 })
167 }
168
169 #[inline]
175 pub(crate) const fn true_expression() -> Self {
176 Self {
177 node: FilterExpressionNode::True,
178 node_count: 1,
179 max_depth: 1,
180 }
181 }
182
183 #[inline]
189 pub(crate) const fn false_expression() -> Self {
190 Self {
191 node: FilterExpressionNode::False,
192 node_count: 1,
193 max_depth: 1,
194 }
195 }
196
197 pub(crate) fn and_unchecked(left: Self, right: Self) -> Self {
208 if left.is_false() || right.is_false() {
209 return Self::false_expression();
210 }
211 if left.is_true() {
212 return right;
213 }
214 if right.is_true() {
215 return left;
216 }
217 Self::combine_and(left, right)
218 }
219
220 pub(crate) fn or_unchecked(left: Self, right: Self) -> Self {
231 if left.is_true() || right.is_true() {
232 return Self::true_expression();
233 }
234 if left.is_false() {
235 return right;
236 }
237 if right.is_false() {
238 return left;
239 }
240 Self::combine_or(left, right)
241 }
242
243 #[inline]
253 pub(crate) fn not_expression(expression: Self) -> Self {
254 let node_count = expression.node_count + 1;
255 let max_depth = expression.max_depth + 1;
256 Self {
257 node: FilterExpressionNode::Not(Box::new(expression)),
258 node_count,
259 max_depth,
260 }
261 }
262
263 pub(crate) fn negated_unchecked(self) -> Self {
269 match self {
270 Self {
271 node: FilterExpressionNode::True,
272 ..
273 } => Self::false_expression(),
274 Self {
275 node: FilterExpressionNode::False,
276 ..
277 } => Self::true_expression(),
278 Self {
279 node: FilterExpressionNode::Not(inner),
280 ..
281 } => *inner,
282 expression => Self::not_expression(expression),
283 }
284 }
285
286 #[inline]
292 pub(crate) const fn is_true(&self) -> bool {
293 matches!(&self.node, FilterExpressionNode::True)
294 }
295
296 #[inline]
302 pub(crate) const fn is_false(&self) -> bool {
303 matches!(&self.node, FilterExpressionNode::False)
304 }
305
306 pub(crate) fn evaluate(&self, metadata: &Metadata, options: FilterMatchOptions) -> MatchOutcome {
317 match &self.node {
318 FilterExpressionNode::Condition(condition) => {
319 condition.evaluate(metadata, options.numeric_comparison_policy())
320 }
321 FilterExpressionNode::And(children) => {
322 MatchOutcome::and(children.iter().map(|child| child.evaluate(metadata, options)))
323 }
324 FilterExpressionNode::Or(children) => {
325 MatchOutcome::or(children.iter().map(|child| child.evaluate(metadata, options)))
326 }
327 FilterExpressionNode::Not(inner) => inner.evaluate(metadata, options).not(),
328 FilterExpressionNode::True => MatchOutcome::True,
329 FilterExpressionNode::False => MatchOutcome::False,
330 }
331 }
332
333 #[cfg(feature = "schema")]
347 pub(crate) fn visit_conditions<F>(&self, visitor: &mut F) -> MetadataResult<()>
348 where
349 F: FnMut(&Condition) -> MetadataResult<()>,
350 {
351 match &self.node {
352 FilterExpressionNode::Condition(condition) => visitor(condition),
353 FilterExpressionNode::And(children) | FilterExpressionNode::Or(children) => {
354 for child in children {
355 child.visit_conditions(visitor)?;
356 }
357 Ok(())
358 }
359 FilterExpressionNode::Not(inner) => inner.visit_conditions(visitor),
360 FilterExpressionNode::True | FilterExpressionNode::False => Ok(()),
361 }
362 }
363
364 pub(crate) fn validate_limits(&self, limits: FilterLimits) -> MetadataResult<()> {
379 let mut node_count = 0;
380 self.validate_limits_at(limits, 1, &mut node_count)
381 }
382
383 pub(crate) fn validate_structure_limits(&self, limits: FilterLimits) -> MetadataResult<()> {
396 if self.max_depth > limits.max_depth() {
397 return Err(MetadataError::FilterLimitExceeded {
398 kind: FilterLimitKind::Depth,
399 value: limits.max_depth() + 1,
400 maximum: limits.max_depth(),
401 });
402 }
403 if self.node_count > limits.max_nodes() {
404 return Err(MetadataError::FilterLimitExceeded {
405 kind: FilterLimitKind::Nodes,
406 value: limits.max_nodes() + 1,
407 maximum: limits.max_nodes(),
408 });
409 }
410 Ok(())
411 }
412
413 fn validate_limits_at(&self, limits: FilterLimits, depth: usize, node_count: &mut usize) -> MetadataResult<()> {
426 if depth > limits.max_depth() {
427 return Err(MetadataError::FilterLimitExceeded {
428 kind: FilterLimitKind::Depth,
429 value: depth,
430 maximum: limits.max_depth(),
431 });
432 }
433 *node_count += 1;
434 if *node_count > limits.max_nodes() {
435 return Err(MetadataError::FilterLimitExceeded {
436 kind: FilterLimitKind::Nodes,
437 value: *node_count,
438 maximum: limits.max_nodes(),
439 });
440 }
441 match &self.node {
442 FilterExpressionNode::Condition(condition) => condition.validate_limits(limits),
443 FilterExpressionNode::And(children) | FilterExpressionNode::Or(children) => {
444 for child in children {
445 child.validate_limits_at(limits, depth + 1, node_count)?;
446 }
447 Ok(())
448 }
449 FilterExpressionNode::Not(inner) => inner.validate_limits_at(limits, depth + 1, node_count),
450 FilterExpressionNode::True | FilterExpressionNode::False => Ok(()),
451 }
452 }
453
454 #[cfg(test)]
457 fn assert_cached_metrics_consistent(&self) {
458 match &self.node {
459 FilterExpressionNode::And(children) | FilterExpressionNode::Or(children) => {
460 for child in children {
461 child.assert_cached_metrics_consistent();
462 }
463 }
464 FilterExpressionNode::Not(inner) => inner.assert_cached_metrics_consistent(),
465 FilterExpressionNode::Condition(_) | FilterExpressionNode::True | FilterExpressionNode::False => {}
466 }
467 let (node_count, max_depth) = self.recursive_metrics();
468 assert_eq!(
469 self.node_count, node_count,
470 "cached node count differs from the expression tree"
471 );
472 assert_eq!(
473 self.max_depth, max_depth,
474 "cached maximum depth differs from the expression tree"
475 );
476 }
477
478 #[cfg(test)]
480 fn recursive_metrics(&self) -> (usize, usize) {
481 match &self.node {
482 FilterExpressionNode::Condition(_) | FilterExpressionNode::True | FilterExpressionNode::False => (1, 1),
483 FilterExpressionNode::And(children) | FilterExpressionNode::Or(children) => {
484 let mut node_count = 1;
485 let mut max_child_depth = 0;
486 for child in children {
487 let (child_node_count, child_max_depth) = child.recursive_metrics();
488 node_count += child_node_count;
489 max_child_depth = max_child_depth.max(child_max_depth);
490 }
491 (node_count, max_child_depth + 1)
492 }
493 FilterExpressionNode::Not(inner) => {
494 let (node_count, max_depth) = inner.recursive_metrics();
495 (node_count + 1, max_depth + 1)
496 }
497 }
498 }
499
500 fn combine_and(left: Self, right: Self) -> Self {
503 let left_same_kind = matches!(&left.node, FilterExpressionNode::And(_));
504 let right_same_kind = matches!(&right.node, FilterExpressionNode::And(_));
505 let (node_count, max_depth) = Self::combined_metrics(&left, &right, left_same_kind, right_same_kind);
506 let mut children = match left {
507 Self {
508 node: FilterExpressionNode::And(children),
509 ..
510 } => children,
511 expression => vec![expression],
512 };
513 match right {
514 Self {
515 node: FilterExpressionNode::And(mut nested),
516 ..
517 } => children.append(&mut nested),
518 expression => children.push(expression),
519 }
520 Self {
521 node: FilterExpressionNode::And(children),
522 node_count,
523 max_depth,
524 }
525 }
526
527 fn combine_or(left: Self, right: Self) -> Self {
530 let left_same_kind = matches!(&left.node, FilterExpressionNode::Or(_));
531 let right_same_kind = matches!(&right.node, FilterExpressionNode::Or(_));
532 let (node_count, max_depth) = Self::combined_metrics(&left, &right, left_same_kind, right_same_kind);
533 let mut children = match left {
534 Self {
535 node: FilterExpressionNode::Or(children),
536 ..
537 } => children,
538 expression => vec![expression],
539 };
540 match right {
541 Self {
542 node: FilterExpressionNode::Or(mut nested),
543 ..
544 } => children.append(&mut nested),
545 expression => children.push(expression),
546 }
547 Self {
548 node: FilterExpressionNode::Or(children),
549 node_count,
550 max_depth,
551 }
552 }
553
554 fn combined_metrics(left: &Self, right: &Self, left_same_kind: bool, right_same_kind: bool) -> (usize, usize) {
569 let node_count = match (left_same_kind, right_same_kind) {
570 (true, true) => left.node_count + right.node_count - 1,
571 (true, false) | (false, true) => left.node_count + right.node_count,
572 (false, false) => left.node_count + right.node_count + 1,
573 };
574 let max_depth = match (left_same_kind, right_same_kind) {
575 (true, true) => left.max_depth.max(right.max_depth),
576 (true, false) => left.max_depth.max(right.max_depth + 1),
577 (false, true) => (left.max_depth + 1).max(right.max_depth),
578 (false, false) => left.max_depth.max(right.max_depth) + 1,
579 };
580 (node_count, max_depth)
581 }
582}
583
584#[cfg(test)]
585mod tests {
586 use super::FilterExpression;
587
588 #[test]
591 fn test_cached_metrics_match_recursive_metrics() {
592 let leaf = FilterExpression::builder()
593 .exists("leaf")
594 .build()
595 .expect("leaf expression should build");
596 leaf.assert_cached_metrics_consistent();
597
598 let left = FilterExpression::builder()
599 .exists("left_1")
600 .exists("left_2")
601 .build()
602 .expect("left expression should build");
603 let right = FilterExpression::builder()
604 .exists("right_1")
605 .exists("right_2")
606 .build()
607 .expect("right expression should build");
608 let flattened = left.try_and(right).expect("flattened AND should build");
609 flattened.assert_cached_metrics_consistent();
610
611 let nested = flattened
612 .try_or(
613 FilterExpression::builder()
614 .exists("alternative")
615 .build()
616 .expect("alternative expression should build"),
617 )
618 .expect("nested OR should build")
619 .try_not()
620 .expect("negated expression should build");
621 nested.assert_cached_metrics_consistent();
622
623 FilterExpression::match_all()
624 .try_and(nested.clone())
625 .expect("true AND expression should simplify")
626 .assert_cached_metrics_consistent();
627 FilterExpression::match_none()
628 .try_or(nested)
629 .expect("false OR expression should simplify")
630 .assert_cached_metrics_consistent();
631 FilterExpression::match_all()
632 .try_not()
633 .expect("constant negation should simplify")
634 .assert_cached_metrics_consistent();
635 }
636}