qubit_metadata/
metadata_filter.rs1use serde::{Deserialize, Serialize};
12
13use crate::{
14 Condition, FilterMatchOptions, Metadata, MetadataFilterBuilder, MetadataResult,
15 MissingKeyPolicy, NumberComparisonPolicy,
16};
17
18#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
20pub(crate) enum FilterExpr {
21 Condition(Condition),
23 And(Vec<FilterExpr>),
25 Or(Vec<FilterExpr>),
27 Not(Box<FilterExpr>),
29 False,
31}
32
33impl FilterExpr {
34 #[inline]
36 fn append_and_child(children: &mut Vec<FilterExpr>, expr: FilterExpr) {
37 match expr {
38 FilterExpr::And(mut nested) => children.append(&mut nested),
39 other => children.push(other),
40 }
41 }
42
43 #[inline]
45 fn append_or_child(children: &mut Vec<FilterExpr>, expr: FilterExpr) {
46 match expr {
47 FilterExpr::Or(mut nested) => children.append(&mut nested),
48 other => children.push(other),
49 }
50 }
51
52 #[inline]
54 pub(crate) fn and(lhs: FilterExpr, rhs: FilterExpr) -> FilterExpr {
55 if matches!(lhs, FilterExpr::False) || matches!(rhs, FilterExpr::False) {
56 return FilterExpr::False;
57 }
58 let mut children = Vec::new();
59 Self::append_and_child(&mut children, lhs);
60 Self::append_and_child(&mut children, rhs);
61 FilterExpr::And(children)
62 }
63
64 #[inline]
66 pub(crate) fn or(lhs: FilterExpr, rhs: FilterExpr) -> FilterExpr {
67 if matches!(lhs, FilterExpr::False) {
68 return rhs;
69 }
70 if matches!(rhs, FilterExpr::False) {
71 return lhs;
72 }
73 let mut children = Vec::new();
74 Self::append_or_child(&mut children, lhs);
75 Self::append_or_child(&mut children, rhs);
76 FilterExpr::Or(children)
77 }
78
79 #[inline]
81 fn matches(&self, meta: &Metadata, options: FilterMatchOptions) -> bool {
82 match self {
83 FilterExpr::Condition(condition) => condition.matches(
84 meta,
85 options.missing_key_policy,
86 options.number_comparison_policy,
87 ),
88 FilterExpr::And(children) => children.iter().all(|expr| expr.matches(meta, options)),
89 FilterExpr::Or(children) => children.iter().any(|expr| expr.matches(meta, options)),
90 FilterExpr::Not(inner) => !inner.matches(meta, options),
91 FilterExpr::False => false,
92 }
93 }
94
95 fn visit_conditions<F>(&self, visitor: &mut F) -> MetadataResult<()>
97 where
98 F: FnMut(&Condition) -> MetadataResult<()>,
99 {
100 match self {
101 FilterExpr::Condition(condition) => visitor(condition),
102 FilterExpr::And(children) | FilterExpr::Or(children) => {
103 for child in children {
104 child.visit_conditions(visitor)?;
105 }
106 Ok(())
107 }
108 FilterExpr::Not(inner) => inner.visit_conditions(visitor),
109 FilterExpr::False => Ok(()),
110 }
111 }
112}
113
114#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
120pub struct MetadataFilter {
121 #[serde(default, skip_serializing_if = "Option::is_none")]
123 expr: Option<FilterExpr>,
124 #[serde(default)]
126 options: FilterMatchOptions,
127}
128
129impl MetadataFilter {
130 #[inline]
132 pub(crate) fn new(expr: Option<FilterExpr>, options: FilterMatchOptions) -> Self {
133 Self { expr, options }
134 }
135
136 #[inline]
138 #[must_use]
139 pub fn builder() -> MetadataFilterBuilder {
140 MetadataFilterBuilder::default()
141 }
142
143 #[inline]
145 #[must_use]
146 pub fn all() -> Self {
147 Self::default()
148 }
149
150 #[inline]
152 #[must_use]
153 pub fn none() -> Self {
154 Self {
155 expr: Some(FilterExpr::False),
156 options: FilterMatchOptions::default(),
157 }
158 }
159
160 #[inline]
162 #[must_use]
163 pub fn options(&self) -> FilterMatchOptions {
164 self.options
165 }
166
167 #[inline]
169 #[must_use]
170 pub fn with_options(mut self, options: FilterMatchOptions) -> Self {
171 self.options = options;
172 self
173 }
174
175 #[inline]
177 #[must_use]
178 pub fn with_missing_key_policy(mut self, missing_key_policy: MissingKeyPolicy) -> Self {
179 self.options.missing_key_policy = missing_key_policy;
180 self
181 }
182
183 #[inline]
185 #[must_use]
186 pub fn with_number_comparison_policy(
187 mut self,
188 number_comparison_policy: NumberComparisonPolicy,
189 ) -> Self {
190 self.options.number_comparison_policy = number_comparison_policy;
191 self
192 }
193
194 #[allow(clippy::should_implement_trait)]
196 #[inline]
197 #[must_use]
198 pub fn not(mut self) -> Self {
199 self.expr = MetadataFilterBuilder::negate_expr(self.expr);
200 self
201 }
202
203 #[inline]
205 #[must_use]
206 pub fn matches(&self, meta: &Metadata) -> bool {
207 self.matches_with_options(meta, self.options)
208 }
209
210 #[inline]
212 #[must_use]
213 pub fn matches_with_options(&self, meta: &Metadata, options: FilterMatchOptions) -> bool {
214 self.expr
215 .as_ref()
216 .is_none_or(|expr| expr.matches(meta, options))
217 }
218
219 pub(crate) fn visit_conditions<F>(&self, mut visitor: F) -> MetadataResult<()>
221 where
222 F: FnMut(&Condition) -> MetadataResult<()>,
223 {
224 if let Some(expr) = &self.expr {
225 expr.visit_conditions(&mut visitor)?;
226 }
227 Ok(())
228 }
229}
230
231impl std::ops::Not for MetadataFilter {
232 type Output = MetadataFilter;
233
234 #[inline]
235 fn not(self) -> Self::Output {
236 MetadataFilter::not(self)
237 }
238}