1use crate::bounds::Bounds;
12use crate::indexable::Indexable;
13
14#[derive(Debug, Clone, Copy, PartialEq)]
19pub enum Predicate {
20 Intersects(Bounds),
23 Within(Bounds),
26 Contains(Bounds),
29 CoveredBy(Bounds),
33 Covers(Bounds),
36 Disjoint(Bounds),
39 Overlaps(Bounds),
42}
43
44impl Predicate {
45 #[must_use]
47 #[inline]
48 pub fn matches(&self, value: &Bounds) -> bool {
49 match self {
50 Predicate::Intersects(q) => q.intersects(value),
51 Predicate::Within(q) => value.within(q),
52 Predicate::Contains(q) => q.within(value),
53 Predicate::CoveredBy(q) => value.covered_by(q),
54 Predicate::Covers(q) => q.covered_by(value),
55 Predicate::Disjoint(q) => q.disjoint(value),
56 Predicate::Overlaps(q) => q.overlaps(value),
57 }
58 }
59
60 #[must_use]
64 #[inline]
65 pub fn could_match(&self, node: &Bounds) -> bool {
66 match self {
67 Predicate::Intersects(q) => q.intersects(node),
68 Predicate::Within(q) | Predicate::CoveredBy(q) | Predicate::Overlaps(q) => {
69 q.intersects(node)
70 }
71 Predicate::Contains(q) | Predicate::Covers(q) => node.contains(q),
72 Predicate::Disjoint(q) => !node.covered_by(q),
75 }
76 }
77
78 #[must_use]
88 #[inline]
89 pub fn covers_all(&self, node: &Bounds) -> bool {
90 match self {
91 Predicate::Intersects(q) | Predicate::CoveredBy(q) => q.contains(node),
92 Predicate::Disjoint(q) => q.disjoint(node),
93 Predicate::Within(_)
94 | Predicate::Contains(_)
95 | Predicate::Covers(_)
96 | Predicate::Overlaps(_) => false,
97 }
98 }
99
100 #[must_use]
102 #[inline]
103 pub fn and<P>(self, other: P) -> AndPredicate<Self, P> {
104 and(self, other)
105 }
106}
107
108impl core::ops::Not for Predicate {
109 type Output = NotPredicate<Self>;
110
111 #[inline]
112 fn not(self) -> Self::Output {
113 not(self)
114 }
115}
116
117pub trait QueryPredicate<T: Indexable> {
123 fn matches(&self, value: &T) -> bool;
125
126 fn could_match(&self, node: &Bounds) -> bool;
128
129 fn covers_all(&self, node: &Bounds) -> bool;
131}
132
133impl<T: Indexable> QueryPredicate<T> for Predicate {
134 #[inline]
135 fn matches(&self, value: &T) -> bool {
136 self.matches(&value.bounds())
137 }
138
139 #[inline]
140 fn could_match(&self, node: &Bounds) -> bool {
141 self.could_match(node)
142 }
143
144 #[inline]
145 fn covers_all(&self, node: &Bounds) -> bool {
146 self.covers_all(node)
147 }
148}
149
150#[derive(Debug, Clone, Copy, PartialEq, Eq)]
152pub struct AndPredicate<Left, Right> {
153 left: Left,
154 right: Right,
155}
156
157#[must_use]
159#[inline]
160pub fn and<Left, Right>(left: Left, right: Right) -> AndPredicate<Left, Right> {
161 AndPredicate { left, right }
162}
163
164impl<T, Left, Right> QueryPredicate<T> for AndPredicate<Left, Right>
165where
166 T: Indexable,
167 Left: QueryPredicate<T>,
168 Right: QueryPredicate<T>,
169{
170 #[inline]
171 fn matches(&self, value: &T) -> bool {
172 self.left.matches(value) && self.right.matches(value)
173 }
174
175 #[inline]
176 fn could_match(&self, node: &Bounds) -> bool {
177 self.left.could_match(node) && self.right.could_match(node)
178 }
179
180 #[inline]
181 fn covers_all(&self, node: &Bounds) -> bool {
182 self.left.covers_all(node) && self.right.covers_all(node)
183 }
184}
185
186#[derive(Debug, Clone, Copy, PartialEq, Eq)]
188pub struct NotPredicate<Inner> {
189 inner: Inner,
190}
191
192#[must_use]
194#[inline]
195pub fn not<Inner>(inner: Inner) -> NotPredicate<Inner> {
196 NotPredicate { inner }
197}
198
199impl<T, Inner> QueryPredicate<T> for NotPredicate<Inner>
200where
201 T: Indexable,
202 Inner: QueryPredicate<T>,
203{
204 #[inline]
205 fn matches(&self, value: &T) -> bool {
206 !self.inner.matches(value)
207 }
208
209 #[inline]
210 fn could_match(&self, node: &Bounds) -> bool {
211 !self.inner.covers_all(node)
212 }
213
214 #[inline]
215 fn covers_all(&self, node: &Bounds) -> bool {
216 !self.inner.could_match(node)
217 }
218}
219
220pub struct Satisfies<F> {
223 condition: F,
224}
225
226#[must_use]
228#[inline]
229pub fn satisfies<F>(condition: F) -> Satisfies<F> {
230 Satisfies { condition }
231}
232
233impl<T, F> QueryPredicate<T> for Satisfies<F>
234where
235 T: Indexable,
236 F: Fn(&T) -> bool,
237{
238 #[inline]
239 fn matches(&self, value: &T) -> bool {
240 (self.condition)(value)
241 }
242
243 #[inline]
244 fn could_match(&self, _node: &Bounds) -> bool {
245 true
246 }
247
248 #[inline]
249 fn covers_all(&self, _node: &Bounds) -> bool {
250 false
251 }
252}
253
254#[cfg(test)]
255mod tests {
256 use super::Predicate;
257 use crate::bounds::Bounds;
258
259 #[test]
260 fn intersects_matches_overlap() {
261 let p = Predicate::Intersects(Bounds::new([0.0, 0.0], [2.0, 2.0]));
262 assert!(p.matches(&Bounds::new([1.0, 1.0], [3.0, 3.0])));
263 assert!(!p.matches(&Bounds::new([5.0, 5.0], [6.0, 6.0])));
264 }
265
266 #[test]
267 fn within_matches_contained() {
268 let p = Predicate::Within(Bounds::new([0.0, 0.0], [10.0, 10.0]));
269 assert!(p.matches(&Bounds::new([2.0, 2.0], [3.0, 3.0])));
270 assert!(!p.matches(&Bounds::new([2.0, 2.0], [12.0, 3.0])));
271 }
272
273 #[test]
274 fn contains_matches_covering() {
275 let p = Predicate::Contains(Bounds::new([4.0, 4.0], [5.0, 5.0]));
276 assert!(p.matches(&Bounds::new([0.0, 0.0], [10.0, 10.0])));
277 assert!(!p.matches(&Bounds::new([0.0, 0.0], [4.5, 4.5])));
278 }
279
280 #[test]
281 fn pruning_skips_disjoint_subtrees() {
282 let p = Predicate::Intersects(Bounds::new([0.0, 0.0], [1.0, 1.0]));
283 assert!(p.could_match(&Bounds::new([0.5, 0.5], [9.0, 9.0])));
284 assert!(!p.could_match(&Bounds::new([5.0, 5.0], [9.0, 9.0])));
285 }
286
287 const QUERY: Bounds = Bounds::new([0.0, 0.0], [10.0, 10.0]);
288 const CONTAINED: Bounds = Bounds::new([2.0, 2.0], [3.0, 3.0]);
289 const OVERLAPPING: Bounds = Bounds::new([5.0, 5.0], [15.0, 15.0]);
290 const DISJOINT: Bounds = Bounds::new([20.0, 20.0], [30.0, 30.0]);
291
292 #[test]
293 fn covers_all_intersects() {
294 let p = Predicate::Intersects(QUERY);
295 assert!(p.covers_all(&CONTAINED));
296 assert!(p.covers_all(&QUERY));
297 assert!(!p.covers_all(&OVERLAPPING));
298 assert!(!p.covers_all(&DISJOINT));
299 }
300
301 #[test]
302 fn covers_all_within_never_assumes_value_dimension() {
303 let p = Predicate::Within(QUERY);
304 assert!(!p.covers_all(&CONTAINED));
305 assert!(!p.covers_all(&QUERY));
306 assert!(!p.covers_all(&OVERLAPPING));
307 assert!(!p.covers_all(&DISJOINT));
308 }
309
310 #[test]
311 fn covers_all_contains_never() {
312 let p = Predicate::Contains(QUERY);
313 assert!(!p.covers_all(&CONTAINED));
314 assert!(!p.covers_all(&QUERY));
315 assert!(!p.covers_all(&OVERLAPPING));
316 assert!(!p.covers_all(&DISJOINT));
317 }
318}