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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//! **Experimental** SQE (Substreams Query Expression) - High-performance boolean expression parser and matcher.
//!
//! > **Warning**: This module is experimental and will replace the current [`crate::expr_parser`]
//! > implementation in a future release. The API may change before stabilization.
//!
//! SQE provides a fast, zero-allocation way to match sets of keys against boolean expressions.
//! It is significantly faster than the current Pest-based implementation:
//!
//! - **Parsing: 5-9x faster** across all expression types
//! - **Matching: 3-14x faster** with zero allocations
//! - **Repeated matching: 9-14x faster** - the main use case sees the biggest wins
//!
//! # Features
//!
//! - **Zero-copy parsing**: The AST stores byte ranges into the original input, not owned strings.
//! - **Zero-allocation matching**: Once parsed, expressions can be matched without any allocations.
//! - **Simple grammar**: Supports AND (`&&`), OR (`||`), implicit AND (whitespace), and grouping `()`.
//! - **Quoted keys**: Keys with spaces can be quoted with single or double quotes.
//!
//! # Example
//!
//! ```rust
//! use substreams::sqe::ExprMatcher;
//!
//! // Parse an expression once
//! let matcher = ExprMatcher::parse("(a || b) && c").unwrap();
//!
//! // Match against different key sets (zero allocations)
//! assert!(matcher.matches_keys(&["a", "c"]));
//! assert!(matcher.matches_keys(&["b", "c"]));
//! assert!(!matcher.matches_keys(&["a"]));
//! ```
//!
//! # Grammar
//!
//! ```text
//! expression := or EOF
//! or := and (OR and)*
//! and := value ((WHITESPACE value) | (AND value))*
//! value := KEY | QUOTED_KEY | '(' or ')'
//! ```
//!
//! Operator precedence (lowest to highest):
//! 1. `||` (OR)
//! 2. `&&` (AND) / implicit AND (whitespace)
//! 3. `()` (grouping)
use ;
use Expression;
/// An experimental expression matcher that can be used to match keys from a given expression.
///
/// > **Warning**: This is an experimental API that will replace [`crate::expr_parser::ExprMatcher`]
/// > in a future release.
///
/// Create a new `ExprMatcher` using [`ExprMatcher::parse`] with the input expression.
/// You can then re-use the matcher to match multiple keys against the same expression,
/// re-using the expression's parsed state with zero allocations.
///
/// # Example
///
/// ```rust
/// use substreams::sqe::ExprMatcher;
///
/// let matcher = ExprMatcher::parse("(a || b) && c").unwrap();
///
/// // Match against different key sets (zero allocations)
/// assert!(matcher.matches_keys(&["a", "c"]));
/// assert!(matcher.matches_keys(&["b", "c"]));
/// assert!(!matcher.matches_keys(&["a"]));
/// ```
/// Creates a new expression matcher from the given input.
///
/// > **Warning**: This is an experimental API that will replace [`crate::expr_matcher`]
/// > in a future release.
///
/// # Panics
///
/// Panics if the input cannot be parsed as a valid expression.
/// Use [`ExprMatcher::new`] if you want to handle parse errors.