sophia_api/term/matcher/
_trait.rs

1use super::*;
2
3/// Generic trait for matching [`Term`]s.
4pub trait TermMatcher {
5    /// The type of term that this TermMatcher contains
6    type Term: Term + ?Sized;
7
8    /// Check whether this matcher matches `t`.
9    fn matches<T2: Term + ?Sized>(&self, term: &T2) -> bool;
10
11    /// Return `None`, unless this matcher can only match a single term,
12    /// in which case this method may return that term.
13    ///
14    /// This method is provided for optimization purposes,
15    /// so implementing it is optional.
16    fn constant(&self) -> Option<&Self::Term> {
17        None
18    }
19
20    /// Converts this [`TermMatcher`] into a [`GraphNameMatcher`]
21    ///
22    /// If you only want to borrow this matcher as a [`GraphNameMatcher`],
23    /// call [`gn`](TermMatcher::gn) on the result of [`matcher_ref`](TermMatcher::matcher_ref).
24    fn gn(self) -> TermMatcherGn<Self>
25    where
26        Self: Sized,
27    {
28        TermMatcherGn(self)
29    }
30
31    /// Return a [`TermMatcher`] that is actually just a reference to this one.
32    fn matcher_ref(&self) -> MatcherRef<'_, Self> {
33        MatcherRef(self)
34    }
35}
36
37/// Matches the wrapped term if any, otherwise matches nothing.
38impl<T> TermMatcher for Option<T>
39where
40    T: Term,
41{
42    type Term = T;
43
44    fn matches<T2: Term + ?Sized>(&self, term: &T2) -> bool {
45        match self {
46            Some(mine) => mine.eq(term.borrow_term()),
47            None => false,
48        }
49    }
50    fn constant(&self) -> Option<&Self::Term> {
51        self.as_ref()
52    }
53}
54
55/// Matches any of the terms in the array.
56impl<T, const N: usize> TermMatcher for [T; N]
57where
58    T: Term,
59{
60    type Term = T;
61
62    fn matches<T2: Term + ?Sized>(&self, term: &T2) -> bool {
63        self.iter().any(|mine| mine.eq(term.borrow_term()))
64    }
65    fn constant(&self) -> Option<&Self::Term> {
66        if N == 1 {
67            Some(&self[0])
68        } else {
69            None
70        }
71    }
72}
73
74/// Matches any of the terms in the slice.
75impl<T> TermMatcher for &[T]
76where
77    T: Term,
78{
79    type Term = T;
80
81    fn matches<T2: Term + ?Sized>(&self, term: &T2) -> bool {
82        self.iter().any(|mine| mine.eq(term.borrow_term()))
83    }
84    fn constant(&self) -> Option<&Self::Term> {
85        if self.len() == 1 {
86            Some(&self[0])
87        } else {
88            None
89        }
90    }
91}
92
93/// Matches only embedded triple whose components match the corresponding matchers.
94impl<S, P, O> TermMatcher for (S, P, O)
95where
96    S: TermMatcher,
97    P: TermMatcher,
98    O: TermMatcher,
99{
100    type Term = S::Term; // not actually used
101
102    fn matches<T2: Term + ?Sized>(&self, term: &T2) -> bool {
103        let (sm, pm, om) = self;
104        match term.triple() {
105            None => false,
106            Some(t) => t.matched_by(sm.matcher_ref(), pm.matcher_ref(), om.matcher_ref()),
107        }
108    }
109}
110
111/// Matches any term if the given kind
112impl TermMatcher for TermKind {
113    type Term = SimpleTerm<'static>; // not actually used
114
115    fn matches<T2: Term + ?Sized>(&self, term: &T2) -> bool {
116        term.kind() == *self
117    }
118}
119
120/// Matches any term satisfying the function.
121impl<F> TermMatcher for F
122where
123    F: Fn(SimpleTerm<'_>) -> bool + ?Sized,
124{
125    type Term = SimpleTerm<'static>; // not actually used
126
127    fn matches<T2: Term + ?Sized>(&self, term: &T2) -> bool {
128        (self)(term.as_simple())
129    }
130}