sophia_api/term/
matcher.rs

1//! I define generic traits and default implementations for *matchers*,
2//! objects that can be used to match zero, one or several terms.
3//!
4//! For a list of matcher implementations,
5//! check [`TermMarcher`'s ](TermMatcher#foreign-impls) and
6//! [`GraphNameMatcher`'s implementors lists](GraphNameMatcher#foreign-impls).
7//!
8//! For methods using matchers (with examples), see for example
9//! [`Triple::matched_by`],
10//! [`Graph::triples_matching`](crate::graph::Graph::triples_matching),
11//! [`MutableGraph::remove_matching`](crate::graph::MutableGraph::remove_matching),
12//! [`MutableGraph::retain_matching`](crate::graph::MutableGraph::retain_matching),
13//! [`Dataset::quads_matching`](crate::dataset::Dataset::quads_matching),
14//! [`MutableDataset::remove_matching`](crate::dataset::MutableDataset::remove_matching),
15//! [`MutableDataset::retain_matching`](crate::dataset::MutableDataset::retain_matching).
16
17use super::*;
18
19mod _any;
20mod _datatype_matcher;
21mod _graph_name_matcher;
22mod _language_tag_matcher;
23mod _matcher_ref;
24mod _not;
25mod _term_matcher_gn;
26mod _trait;
27
28pub use _any::Any;
29pub use _datatype_matcher::*;
30pub use _graph_name_matcher::*;
31pub use _language_tag_matcher::*;
32pub use _matcher_ref::*;
33pub use _not::Not;
34pub use _term_matcher_gn::*;
35pub use _trait::*;
36
37#[cfg(test)]
38mod test {
39    use super::*;
40    use crate::ns::xsd;
41    use sophia_iri::IriRef;
42
43    const T1: IriRef<&str> = IriRef::new_unchecked_const("tag:t1");
44    const T2: IriRef<&str> = IriRef::new_unchecked_const("tag:t2");
45    const T3: IriRef<&str> = IriRef::new_unchecked_const("tag:t3");
46
47    fn is_term_matcher<M: TermMatcher>(_: M) {}
48
49    #[allow(dead_code)] // just check this compiles
50    fn check_term_macher_implementations() {
51        is_term_matcher(Any);
52        is_term_matcher(Some(T1));
53        is_term_matcher([T1, T2]);
54        is_term_matcher(&[T1, T2][..]);
55        is_term_matcher(|t: SimpleTerm| t != T1);
56        is_term_matcher(TermKind::Iri);
57        is_term_matcher(([T1], [T2], [T3]));
58        is_term_matcher([T1, T2].matcher_ref());
59        is_term_matcher(Any * xsd::string);
60    }
61
62    fn is_graph_name_matcher<M: GraphNameMatcher>(_: M) {}
63
64    #[allow(dead_code)] // just check this compiles
65    fn check_graph_name_macher_implementations() {
66        is_graph_name_matcher(Any);
67        is_graph_name_matcher(Some(Some(T1)));
68        is_graph_name_matcher([Some(T1), Some(T2), None]);
69        is_graph_name_matcher(&[Some(T1), Some(T2), None][..]);
70        is_graph_name_matcher(|t: Option<SimpleTerm>| t.is_some());
71        is_graph_name_matcher(Not(|t: Option<SimpleTerm>| t.is_some()));
72        is_graph_name_matcher([T1, T2].gn());
73        is_graph_name_matcher(Some(TermKind::Iri));
74        is_graph_name_matcher(Some(([T1], [T2], [T3])));
75        is_graph_name_matcher([Some(T1)].matcher_ref());
76        is_graph_name_matcher(Not([Some(T1)].matcher_ref()));
77    }
78
79    #[test]
80    fn option() {
81        let none: Option<IriRef<&str>> = None;
82        assert!(!none.matches(&T1));
83        assert!(!none.matches(&T2));
84        assert!(!none.matches(&T3));
85        assert_eq!(none.constant(), None);
86
87        let some = Some(T1);
88        assert!(some.matches(&T1));
89        assert!(!some.matches(&T2));
90        assert!(!none.matches(&T3));
91        assert_eq!(some.constant(), Some(&T1));
92    }
93
94    #[test]
95    fn array() {
96        let a0: [IriRef<&str>; 0] = [];
97        assert!(!a0.matches(&T1));
98        assert!(!a0.matches(&T2));
99        assert!(!a0.matches(&T3));
100        assert_eq!(a0.constant(), None);
101
102        let a1 = [T1];
103        assert!(a1.matches(&T1));
104        assert!(!a1.matches(&T2));
105        assert!(!a1.matches(&T3));
106        assert_eq!(a1.constant(), Some(&T1));
107
108        let a2 = [T1, T2];
109        assert!(a2.matches(&T1));
110        assert!(a2.matches(&T2));
111        assert!(!a2.matches(&T3));
112        assert_eq!(a2.constant(), None);
113
114        let a3 = [T1, T2, T3];
115        assert!(a3.matches(&T1));
116        assert!(a3.matches(&T2));
117        assert!(a3.matches(&T3));
118        assert_eq!(a3.constant(), None);
119    }
120
121    #[test]
122    fn slice() {
123        let a0: [IriRef<&str>; 0] = [];
124        let s0 = &a0[..];
125        assert!(!s0.matches(&T1));
126        assert!(!s0.matches(&T2));
127        assert!(!s0.matches(&T3));
128        assert_eq!(s0.constant(), None);
129
130        let a1 = [T1];
131        let s1 = &a1[..];
132        assert!(s1.matches(&T1));
133        assert!(!s1.matches(&T2));
134        assert!(!s1.matches(&T3));
135        assert_eq!(s1.constant(), Some(&T1));
136
137        let a2 = [T1, T2];
138        let s2 = &a2[..];
139        assert!(s2.matches(&T1));
140        assert!(s2.matches(&T2));
141        assert!(!s2.matches(&T3));
142        assert_eq!(s2.constant(), None);
143
144        let a3 = [T1, T2, T3];
145        let s3 = &a3[..];
146        assert!(s3.matches(&T1));
147        assert!(s3.matches(&T2));
148        assert!(s3.matches(&T3));
149        assert_eq!(s3.constant(), None);
150    }
151
152    #[test]
153    fn term_kind() {
154        assert!(TermKind::Iri.matches(&T1));
155        assert!(!TermKind::BlankNode.matches(&T1));
156    }
157
158    #[test]
159    fn tuple_as_embedded_triple() {
160        let et = SimpleTerm::Triple(Box::new([T1, T2, T3].map(SimpleTerm::from_term)));
161        assert!(([T1], TermKind::Iri, Any).matches(&et));
162        assert!(!([T2], TermKind::Iri, Any).matches(&et));
163        assert!(!([T1], TermKind::BlankNode, Any).matches(&et));
164        assert!(!([T1], TermKind::Iri, [T1]).matches(&et));
165    }
166
167    #[test]
168    fn closure() {
169        let c = |t: SimpleTerm| t != T1;
170        assert!(!TermMatcher::matches(&c, &T1));
171        assert!(TermMatcher::matches(&c, &T2));
172        assert!(TermMatcher::matches(&c, &T3));
173        assert!(TermMatcher::constant(&c).is_none());
174    }
175
176    #[test]
177    fn any() {
178        assert!(TermMatcher::matches(&Any, &T1));
179        assert!(TermMatcher::matches(&Any, &T2));
180        assert!(TermMatcher::matches(&Any, &T3));
181        assert!(TermMatcher::constant(&Any).is_none());
182    }
183
184    #[test]
185    fn not() {
186        assert!(Not(TermKind::BlankNode).matches(&T1));
187        assert!(Not([T1, T2]).matches(&T3));
188    }
189
190    #[test]
191    fn datatype_matcher() {
192        let m1 = Any * xsd::string; // testing Mul<NsTerm>
193        assert!(!TermMatcher::matches(&m1, &T1));
194        assert!(!TermMatcher::matches(&m1, &42));
195        assert!(TermMatcher::matches(&m1, "hello"));
196        let m1 = Any * xsd::string.iri().unwrap(); // testing Mul<IriRef>
197        assert!(!TermMatcher::matches(&m1, &T1));
198        assert!(!TermMatcher::matches(&m1, &42));
199        assert!(TermMatcher::matches(&m1, "hello"));
200    }
201
202    #[test]
203    fn language_tag_matcher() {
204        let en = LanguageTag::new_unchecked("en");
205        let enus = LanguageTag::new_unchecked("en-US");
206        let fr = LanguageTag::new_unchecked("fr");
207        let m1 = Any * en; // testing Mul<NsTerm>
208        assert!(!TermMatcher::matches(&m1, &T1));
209        assert!(!TermMatcher::matches(&m1, &42));
210        assert!(!TermMatcher::matches(&m1, "hello"));
211        assert!(TermMatcher::matches(&m1, &("hello" * en)));
212        assert!(!TermMatcher::matches(&m1, &("hello" * enus)));
213        assert!(!TermMatcher::matches(&m1, &("hello" * fr)));
214    }
215
216    #[test]
217    fn matcher_ref() {
218        let c = [T1].matcher_ref();
219        assert!(c.matches(&T1));
220        assert!(!c.matches(&T2));
221        assert!(!c.matches(&T3));
222        assert_eq!(c.constant(), Some(&T1));
223    }
224
225    const DEFAULT: Option<&IriRef<&str>> = None;
226
227    #[test]
228    fn graph_name_option() {
229        let none: Option<Option<IriRef<&str>>> = None;
230        assert!(!none.matches(DEFAULT));
231        assert!(!none.matches(Some(&T1)));
232        assert!(!none.matches(Some(&T2)));
233        assert!(!none.matches(Some(&T3)));
234        assert_eq!(none.constant(), None);
235
236        let some = Some(Some(T1));
237        assert!(!some.matches(DEFAULT));
238        assert!(some.matches(Some(&T1)));
239        assert!(!some.matches(Some(&T2)));
240        assert!(!none.matches(Some(&T3)));
241        assert_eq!(some.constant(), Some(Some(&T1)));
242    }
243
244    #[test]
245    fn graph_name_array() {
246        let a0: [Option<&IriRef<&str>>; 0] = [];
247        assert!(!a0.matches(DEFAULT));
248        assert!(!a0.matches(Some(&T1)));
249        assert!(!a0.matches(Some(&T2)));
250        assert!(!a0.matches(Some(&T3)));
251        assert_eq!(a0.constant(), None);
252
253        let a1 = [Some(T1)];
254        assert!(!a1.matches(DEFAULT));
255        assert!(a1.matches(Some(&T1)));
256        assert!(!a1.matches(Some(&T2)));
257        assert!(!a1.matches(Some(&T3)));
258        assert_eq!(a1.constant(), Some(Some(&T1)));
259
260        let a2 = [Some(T1), None];
261        assert!(a2.matches(DEFAULT));
262        assert!(a2.matches(Some(&T1)));
263        assert!(!a2.matches(Some(&T2)));
264        assert!(!a2.matches(Some(&T3)));
265        assert_eq!(a2.constant(), None);
266
267        let a3 = [Some(T1), None, Some(T3)];
268        assert!(a3.matches(DEFAULT));
269        assert!(a3.matches(Some(&T1)));
270        assert!(!a3.matches(Some(&T2)));
271        assert!(a3.matches(Some(&T3)));
272        assert_eq!(a3.constant(), None);
273    }
274
275    #[test]
276    fn graph_name_slice() {
277        let a0: [Option<&IriRef<&str>>; 0] = [];
278        let s0 = &a0[..];
279        assert!(!s0.matches(DEFAULT));
280        assert!(!s0.matches(Some(&T1)));
281        assert!(!s0.matches(Some(&T2)));
282        assert!(!s0.matches(Some(&T3)));
283        assert_eq!(s0.constant(), None);
284
285        let a1 = [Some(T1)];
286        let s1 = &a1[..];
287        assert!(!s1.matches(DEFAULT));
288        assert!(s1.matches(Some(&T1)));
289        assert!(!s1.matches(Some(&T2)));
290        assert!(!s1.matches(Some(&T3)));
291        assert_eq!(s1.constant(), Some(Some(&T1)));
292
293        let a2 = [Some(T1), None];
294        let s2 = &a2[..];
295        assert!(s2.matches(DEFAULT));
296        assert!(s2.matches(Some(&T1)));
297        assert!(!s2.matches(Some(&T2)));
298        assert!(!s2.matches(Some(&T3)));
299        assert_eq!(s2.constant(), None);
300
301        let a3 = [Some(T1), None, Some(T3)];
302        let s3 = &a3[..];
303        assert!(s3.matches(DEFAULT));
304        assert!(s3.matches(Some(&T1)));
305        assert!(!s3.matches(Some(&T2)));
306        assert!(s3.matches(Some(&T3)));
307        assert_eq!(s3.constant(), None);
308    }
309
310    #[test]
311    fn graph_name_term_kind() {
312        assert!(Some(TermKind::Iri).matches(Some(&T1)));
313        assert!(!Some(TermKind::BlankNode).matches(Some(&T1)));
314    }
315
316    #[test]
317    fn graph_name_tuple_as_embedded_triple() {
318        let et = SimpleTerm::Triple(Box::new([T1, T2, T3].map(SimpleTerm::from_term)));
319        let gn = Some(&et);
320        assert!(Some(([T1], TermKind::Iri, Any)).matches(gn));
321        assert!(!Some(([T2], TermKind::Iri, Any)).matches(gn));
322        assert!(!Some(([T1], TermKind::BlankNode, Any)).matches(gn));
323        assert!(!Some(([T1], TermKind::Iri, [T1])).matches(gn));
324    }
325
326    #[test]
327    fn graph_name_closure() {
328        let c = |t: Option<SimpleTerm>| !graph_name_eq(t, Some(&T1));
329        assert!(GraphNameMatcher::matches(&c, DEFAULT));
330        assert!(!GraphNameMatcher::matches(&c, Some(&T1)));
331        assert!(GraphNameMatcher::matches(&c, Some(&T2)));
332        assert!(GraphNameMatcher::matches(&c, Some(&T3)));
333        assert!(GraphNameMatcher::constant(&c).is_none());
334    }
335
336    #[test]
337    fn graph_name_any() {
338        assert!(GraphNameMatcher::matches(&Any, DEFAULT));
339        assert!(GraphNameMatcher::matches(&Any, Some(&T1)));
340        assert!(GraphNameMatcher::matches(&Any, Some(&T2)));
341        assert!(GraphNameMatcher::matches(&Any, Some(&T3)));
342        assert!(GraphNameMatcher::constant(&Any).is_none());
343    }
344
345    #[test]
346    fn graph_name_not() {
347        assert!(GraphNameMatcher::matches(&Not([DEFAULT]), Some(&T1)));
348        assert!(!GraphNameMatcher::matches(&Not([T1, T2].gn()), Some(&T2)));
349        assert!(GraphNameMatcher::matches(&Not([T1, T2].gn()), Some(&T3)));
350    }
351
352    #[test]
353    fn graph_name_term_matcher_gn() {
354        let a1 = [T1].gn();
355        assert!(!a1.matches(DEFAULT));
356        assert!(a1.matches(Some(&T1)));
357        assert!(!a1.matches(Some(&T2)));
358        assert!(!a1.matches(Some(&T3)));
359        assert_eq!(a1.constant(), Some(Some(&T1)));
360
361        let a2 = [T1, T2].gn();
362        assert!(!a2.matches(DEFAULT));
363        assert!(a2.matches(Some(&T1)));
364        assert!(a2.matches(Some(&T2)));
365        assert!(!a2.matches(Some(&T3)));
366        assert_eq!(a2.constant(), None);
367    }
368
369    #[test]
370    fn graph_name_matcher_ref() {
371        let c = [Some(T1)].matcher_ref();
372        assert!(!c.matches(DEFAULT));
373        assert!(c.matches(Some(&T1)));
374        assert!(!c.matches(Some(&T2)));
375        assert!(!c.matches(Some(&T3)));
376        assert_eq!(c.constant(), Some(Some(&T1)));
377    }
378}