1use crate::term::matcher::{GraphNameMatcher, TermMatcher};
7use crate::term::{graph_name_eq, GraphName, Term};
8
9pub type QBorrowTerm<'a, T> = <<T as Quad>::Term as Term>::BorrowTerm<'a>;
11pub type Spog<T> = ([T; 3], GraphName<T>);
13pub type Gspo<T> = (GraphName<T>, [T; 3]);
16
17pub trait Quad {
20 type Term: Term;
22
23 fn s(&self) -> QBorrowTerm<Self>;
25
26 fn p(&self) -> QBorrowTerm<Self>;
28
29 fn o(&self) -> QBorrowTerm<Self>;
31
32 fn g(&self) -> GraphName<QBorrowTerm<Self>>;
36
37 #[inline]
41 fn spog(&self) -> Spog<QBorrowTerm<Self>> {
42 ([self.s(), self.p(), self.o()], self.g())
43 }
44
45 fn to_s(self) -> Self::Term
47 where
48 Self: Sized,
49 {
50 let [s, _, _] = self.to_spog().0;
51 s
52 }
53
54 fn to_p(self) -> Self::Term
56 where
57 Self: Sized,
58 {
59 let [_, p, _] = self.to_spog().0;
60 p
61 }
62
63 fn to_o(self) -> Self::Term
65 where
66 Self: Sized,
67 {
68 let [_, _, o] = self.to_spog().0;
69 o
70 }
71
72 fn to_g(self) -> GraphName<Self::Term>
74 where
75 Self: Sized,
76 {
77 self.to_spog().1
78 }
79
80 fn to_spog(self) -> Spog<Self::Term>
84 where
85 Self: Sized;
86
87 fn matched_by<S, P, O, G>(&self, sm: S, pm: P, om: O, gm: G) -> bool
89 where
90 S: TermMatcher,
91 P: TermMatcher,
92 O: TermMatcher,
93 G: GraphNameMatcher,
94 {
95 sm.matches(&self.s())
96 && pm.matches(&self.p())
97 && om.matches(&self.o())
98 && gm.matches(self.g().as_ref())
99 }
100
101 #[inline]
105 fn eq<T: Quad>(&self, other: T) -> bool {
106 self.eq_spog(other.s(), other.p(), other.o(), other.g())
107 }
108
109 fn eq_spog<S: Term, P: Term, O: Term, G: Term>(
113 &self,
114 s: S,
115 p: P,
116 o: O,
117 g: GraphName<G>,
118 ) -> bool {
119 self.s().eq(s) && self.p().eq(p) && self.o().eq(o) && graph_name_eq(self.g(), g)
120 }
121
122 fn into_triple(self) -> [Self::Term; 3]
134 where
135 Self: Sized,
136 {
137 self.to_spog().0
138 }
139}
140
141impl<T: Term> Quad for [T; 4] {
142 type Term = T;
143
144 fn s(&self) -> QBorrowTerm<Self> {
145 self[0].borrow_term()
146 }
147 fn p(&self) -> QBorrowTerm<Self> {
148 self[1].borrow_term()
149 }
150 fn o(&self) -> QBorrowTerm<Self> {
151 self[2].borrow_term()
152 }
153 fn g(&self) -> GraphName<QBorrowTerm<Self>> {
154 Some(self[3].borrow_term())
155 }
156 fn to_s(self) -> Self::Term {
157 let [s, _, _, _] = self;
158 s
159 }
160 fn to_p(self) -> Self::Term {
161 let [_, p, _, _] = self;
162 p
163 }
164 fn to_o(self) -> Self::Term {
165 let [_, _, o, _] = self;
166 o
167 }
168 fn to_g(self) -> GraphName<Self::Term> {
169 let [_, _, _, g] = self;
170 Some(g)
171 }
172 fn to_spog(self) -> Spog<Self::Term> {
173 let [s, p, o, g] = self;
174 ([s, p, o], Some(g))
175 }
176}
177
178impl<T: Term> Quad for ([T; 3], GraphName<T>) {
180 type Term = T;
181
182 fn s(&self) -> QBorrowTerm<Self> {
183 self.0[0].borrow_term()
184 }
185 fn p(&self) -> QBorrowTerm<Self> {
186 self.0[1].borrow_term()
187 }
188 fn o(&self) -> QBorrowTerm<Self> {
189 self.0[2].borrow_term()
190 }
191 fn g(&self) -> GraphName<QBorrowTerm<Self>> {
192 self.1.as_ref().map(|gn| gn.borrow_term())
193 }
194 fn to_s(self) -> Self::Term {
195 let [s, _, _] = self.0;
196 s
197 }
198 fn to_p(self) -> Self::Term {
199 let [_, p, _] = self.0;
200 p
201 }
202 fn to_o(self) -> Self::Term {
203 let [_, _, o] = self.0;
204 o
205 }
206 fn to_g(self) -> GraphName<Self::Term> {
207 self.1
208 }
209 fn to_spog(self) -> Spog<Self::Term> {
210 self
211 }
212}
213
214impl<T: Term> Quad for (GraphName<T>, [T; 3]) {
216 type Term = T;
217
218 fn s(&self) -> QBorrowTerm<Self> {
219 self.1[0].borrow_term()
220 }
221 fn p(&self) -> QBorrowTerm<Self> {
222 self.1[1].borrow_term()
223 }
224 fn o(&self) -> QBorrowTerm<Self> {
225 self.1[2].borrow_term()
226 }
227 fn g(&self) -> GraphName<QBorrowTerm<'_, Self>> {
228 self.0.as_ref().map(|gn| gn.borrow_term())
229 }
230 fn to_s(self) -> Self::Term {
231 let [s, _, _] = self.1;
232 s
233 }
234 fn to_p(self) -> Self::Term {
235 let [_, p, _] = self.1;
236 p
237 }
238 fn to_o(self) -> Self::Term {
239 let [_, _, o] = self.1;
240 o
241 }
242 fn to_g(self) -> GraphName<Self::Term> {
243 self.0
244 }
245 fn to_spog(self) -> Spog<Self::Term> {
246 let (g, spo) = self;
247 (spo, g)
248 }
249}
250
251pub fn iter_spog<T: Quad>(q: T) -> impl Iterator<Item = T::Term> {
253 let (spo, g) = q.to_spog();
254 spo.into_iter().chain(g)
255}
256
257#[cfg(test)]
258mod check_implementability {
259 use super::*;
260 use crate::term::*;
261 use mownstr::MownStr;
262
263 #[derive(Clone, Copy, Debug)]
264 struct MyBnode(usize);
265
266 impl Term for MyBnode {
267 type BorrowTerm<'x> = Self;
268
269 fn kind(&self) -> TermKind {
270 TermKind::BlankNode
271 }
272 fn bnode_id(&self) -> Option<BnodeId<MownStr>> {
273 Some(BnodeId::new_unchecked(MownStr::from(format!(
274 "b{}",
275 self.0
276 ))))
277 }
278 fn borrow_term(&self) -> Self::BorrowTerm<'_> {
279 *self
280 }
281 }
282
283 #[derive(Clone, Copy, Debug)]
284 struct MyQuad([usize; 4]);
285
286 impl Quad for MyQuad {
287 type Term = MyBnode;
288
289 fn s(&self) -> QBorrowTerm<Self> {
290 MyBnode(self.0[0])
291 }
292 fn p(&self) -> QBorrowTerm<Self> {
293 MyBnode(self.0[1])
294 }
295 fn o(&self) -> QBorrowTerm<Self> {
296 MyBnode(self.0[2])
297 }
298 fn g(&self) -> GraphName<QBorrowTerm<Self>> {
299 match self.0[3] {
300 0 => None,
301 n => Some(MyBnode(n)),
302 }
303 }
304 fn to_s(self) -> Self::Term {
305 self.s()
306 }
307 fn to_p(self) -> Self::Term {
308 self.p()
309 }
310 fn to_o(self) -> Self::Term {
311 self.o()
312 }
313 fn to_g(self) -> GraphName<Self::Term> {
314 self.g()
315 }
316 fn to_spog(self) -> Spog<Self::Term> {
317 ([self.s(), self.p(), self.o()], self.g())
318 }
319 }
320
321 #[allow(dead_code)] fn check_quad_impl(t: [SimpleTerm; 4]) {
323 fn foo<T: Quad>(t: T) {
324 println!("{:?}", t.s().kind());
325 }
326 let rt = t.spog();
327 foo(rt);
328 {
329 let rt2 = t.spog();
330 foo(rt2);
331 }
332 foo(rt);
333 foo(rt.spog());
334 foo(t);
335
336 let mt = MyQuad([1, 2, 3, 0]);
337 let rmt = mt.spog();
338 foo(rmt);
339 {
340 let rmt2 = mt.spog();
341 foo(rmt2);
342 }
343 foo(rmt);
344 foo(rmt.spog());
345 foo(mt);
346 }
347}
348
349#[cfg(test)]
350mod test_quad {
351 use super::*;
352 use crate::term::SimpleTerm;
353 use sophia_iri::IriRef;
354
355 const S: IriRef<&str> = IriRef::new_unchecked_const("tag:s");
356 const P: IriRef<&str> = IriRef::new_unchecked_const("tag:o");
357 const O: IriRef<&str> = IriRef::new_unchecked_const("tag:p");
358 const G: GraphName<IriRef<&str>> = Some(IriRef::new_unchecked_const("tag:g"));
359
360 #[test]
361 fn quad_matched_by() {
362 use crate::term::matcher::Any;
363 let q = ([S, P, O], G);
364
365 assert!(q.matched_by(Any, Any, Any, Any));
366 assert!(q.matched_by([S], [P], [O], [G]));
367 assert!(q.matched_by([O, S], [S, P], [P, O], [None, G]));
368 let istag = |t: SimpleTerm| t.iri().map(|iri| iri.starts_with("tag:")).unwrap_or(false);
369 assert!(q.matched_by(istag, istag, istag, istag.gn()));
370
371 let none: Option<IriRef<&str>> = None;
372 assert!(!q.matched_by(none, Any, Any, Any));
373 assert!(!q.matched_by(Any, none, Any, Any));
374 assert!(!q.matched_by(Any, Any, none, Any));
375 assert!(!q.matched_by(Any, Any, Any, none.gn()));
376 assert!(!q.matched_by([P, O], Any, Any, Any));
377 assert!(!q.matched_by(Any, [S, O], Any, Any));
378 assert!(!q.matched_by(Any, Any, [S, P], Any));
379 assert!(!q.matched_by(Any, Any, Any, [S, P, O].gn()));
380 let notag = |t: SimpleTerm| t.iri().map(|iri| !iri.starts_with("tag:")).unwrap_or(true);
381 assert!(!q.matched_by(notag, Any, Any, Any));
382 assert!(!q.matched_by(Any, notag, Any, Any));
383 assert!(!q.matched_by(Any, Any, notag, Any));
384 assert!(!q.matched_by(Any, Any, Any, notag.gn()));
385
386 let ts = vec![
387 ([S, P, S], G),
388 ([S, P, P], G),
389 ([S, P, O], G),
390 ([P, P, S], G),
391 ([P, P, P], G),
392 ([P, P, O], G),
393 ([O, P, S], G),
394 ([O, P, P], G),
395 ([O, P, O], G),
396 ([S, P, S], None),
397 ([P, P, P], None),
398 ([O, P, O], None),
399 ];
400 let c = ts
401 .iter()
402 .filter(|t| t.matched_by([S, O], Any, [S, O], Any))
403 .count();
404 assert_eq!(c, 6);
405
406 let default = G.filter(|_| false);
407 let c = ts
408 .iter()
409 .filter(|t| t.matched_by([S], Any, Any, [default]))
410 .count();
411 assert_eq!(c, 1);
412 }
413}