1use crate::quad::Spog;
20use crate::term::{matcher::TermMatcher, GraphName, Term};
21
22pub type TBorrowTerm<'a, T> = <<T as Triple>::Term as Term>::BorrowTerm<'a>;
24
25pub trait Triple: Sized {
28 type Term: Term;
30
31 fn s(&self) -> TBorrowTerm<Self>;
33
34 fn p(&self) -> TBorrowTerm<Self>;
36
37 fn o(&self) -> TBorrowTerm<Self>;
39
40 #[inline]
44 fn spo(&self) -> [TBorrowTerm<Self>; 3] {
45 [self.s(), self.p(), self.o()]
46 }
47
48 fn to_s(self) -> Self::Term {
50 let [s, _, _] = self.to_spo();
51 s
52 }
53
54 fn to_p(self) -> Self::Term {
56 let [_, p, _] = self.to_spo();
57 p
58 }
59
60 fn to_o(self) -> Self::Term {
62 let [_, _, o] = self.to_spo();
63 o
64 }
65
66 fn to_spo(self) -> [Self::Term; 3];
70
71 fn matched_by<S, P, O>(&self, sm: S, pm: P, om: O) -> bool
73 where
74 S: TermMatcher,
75 P: TermMatcher,
76 O: TermMatcher,
77 {
78 sm.matches(&self.s()) && pm.matches(&self.p()) && om.matches(&self.o())
79 }
80
81 #[inline]
85 fn eq<T: Triple>(&self, other: T) -> bool {
86 self.eq_spo(other.s(), other.p(), other.o())
87 }
88
89 fn eq_spo<S: Term, P: Term, O: Term>(&self, s: S, p: P, o: O) -> bool {
93 self.s().eq(s) && self.p().eq(p) && self.o().eq(o)
94 }
95
96 fn into_quad(self) -> Spog<Self::Term> {
110 (self.to_spo(), None)
111 }
112
113 fn into_quad_from(self, graph_name: GraphName<Self::Term>) -> Spog<Self::Term> {
117 (self.to_spo(), graph_name)
118 }
119}
120
121impl<T: Term> Triple for [T; 3] {
122 type Term = T;
123
124 fn s(&self) -> TBorrowTerm<Self> {
125 self[0].borrow_term()
126 }
127 fn p(&self) -> TBorrowTerm<Self> {
128 self[1].borrow_term()
129 }
130 fn o(&self) -> TBorrowTerm<Self> {
131 self[2].borrow_term()
132 }
133 fn to_spo(self) -> [Self::Term; 3] {
134 self
135 }
136}
137
138#[cfg(test)]
139mod check_implementability {
140 use super::*;
141 use crate::term::*;
142 use mownstr::MownStr;
143
144 #[derive(Clone, Copy, Debug)]
145 struct MyBnode(usize);
146
147 impl Term for MyBnode {
148 type BorrowTerm<'x> = Self;
149
150 fn kind(&self) -> TermKind {
151 TermKind::BlankNode
152 }
153 fn bnode_id(&self) -> Option<BnodeId<MownStr>> {
154 Some(BnodeId::new_unchecked(MownStr::from(format!(
155 "b{}",
156 self.0
157 ))))
158 }
159 fn borrow_term(&self) -> Self::BorrowTerm<'_> {
160 *self
161 }
162 }
163
164 #[derive(Clone, Copy, Debug)]
165 struct MyTriple([usize; 3]);
166
167 impl Triple for MyTriple {
168 type Term = MyBnode;
169
170 fn s(&self) -> TBorrowTerm<Self> {
171 MyBnode(self.0[0])
172 }
173 fn p(&self) -> TBorrowTerm<Self> {
174 MyBnode(self.0[1])
175 }
176 fn o(&self) -> TBorrowTerm<Self> {
177 MyBnode(self.0[2])
178 }
179 fn to_s(self) -> Self::Term {
180 self.s()
181 }
182 fn to_p(self) -> Self::Term {
183 self.p()
184 }
185 fn to_o(self) -> Self::Term {
186 self.o()
187 }
188 fn to_spo(self) -> [Self::Term; 3] {
189 [self.s(), self.p(), self.o()]
190 }
191 }
192
193 #[allow(dead_code)] fn check_triple_impl(t: [SimpleTerm; 3]) {
195 fn foo<T: Triple>(t: T) {
196 println!("{:?}", t.s().kind());
197 }
198 let rt = t.spo();
199 foo(rt);
200 {
201 let rt2 = t.spo();
202 foo(rt2);
203 }
204 foo(rt);
205 foo(rt.spo());
206 foo(t);
207
208 let mt = MyTriple([1, 2, 3]);
209 let rmt = mt.spo();
210 foo(rmt);
211 {
212 let rmt2 = mt.spo();
213 foo(rmt2);
214 }
215 foo(rmt);
216 foo(rmt.spo());
217 foo(mt);
218 }
219}
220
221#[cfg(test)]
222mod test_triple {
223 use super::*;
224 use crate::term::SimpleTerm;
225 use sophia_iri::IriRef;
226
227 const S: IriRef<&str> = IriRef::new_unchecked_const("tag:s");
228 const P: IriRef<&str> = IriRef::new_unchecked_const("tag:o");
229 const O: IriRef<&str> = IriRef::new_unchecked_const("tag:p");
230
231 #[test]
232 fn triple_matched_by() {
233 use crate::term::matcher::Any;
234 let t = [S, P, O];
235
236 assert!(t.matched_by(Any, Any, Any));
237 assert!(t.matched_by([S], [P], [O]));
238 assert!(t.matched_by([O, S], [S, P], [P, O]));
239 let istag = |t: SimpleTerm| t.iri().map(|iri| iri.starts_with("tag:")).unwrap_or(false);
240 assert!(t.matched_by(istag, istag, istag));
241
242 let none: Option<IriRef<&str>> = None;
243 assert!(!t.matched_by(none, Any, Any));
244 assert!(!t.matched_by(Any, none, Any));
245 assert!(!t.matched_by(Any, Any, none));
246 assert!(!t.matched_by([P, O], Any, Any));
247 assert!(!t.matched_by(Any, [S, O], Any));
248 assert!(!t.matched_by(Any, Any, [S, P]));
249 let notag = |t: SimpleTerm| t.iri().map(|iri| !iri.starts_with("tag:")).unwrap_or(true);
250 assert!(!t.matched_by(notag, Any, Any));
251 assert!(!t.matched_by(Any, notag, Any));
252 assert!(!t.matched_by(Any, Any, notag));
253
254 let ts = vec![
255 [S, P, S],
256 [S, P, P],
257 [S, P, O],
258 [P, P, S],
259 [P, P, P],
260 [P, P, O],
261 [O, P, S],
262 [O, P, P],
263 [O, P, O],
264 ];
265 let c = ts
266 .iter()
267 .filter(|t| t.matched_by([S, O], Any, [S, O]))
268 .count();
269 assert_eq!(c, 4);
270 }
271}