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