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