1use std::{cmp::Ordering, fmt};
2
3use iref::{Iri, IriBuf};
4
5use crate::{
6 interpretation::Interpret,
7 vocabulary::{
8 ByRef, EmbedIntoVocabulary, EmbeddedIntoVocabulary, ExtractFromVocabulary,
9 ExtractedFromVocabulary, TryExtractFromVocabulary,
10 },
11 GraphLabel, Id, Interpretation, LexicalGraphLabelRef, LexicalObjectRef, LexicalSubjectRef,
12 Object, RdfDisplay, Term, Triple,
13};
14
15#[cfg(feature = "contextual")]
16use contextual::{DisplayWithContext, WithContext};
17
18#[cfg(feature = "contextual")]
19use crate::RdfDisplayWithContext;
20
21pub type LexicalQuad = Quad<Id, IriBuf, Object, GraphLabel>;
23
24pub type LexicalQuadRef<'a> =
26 Quad<LexicalSubjectRef<'a>, &'a Iri, LexicalObjectRef<'a>, LexicalGraphLabelRef<'a>>;
27
28#[derive(Clone, Copy, Eq, Ord, Hash, Debug)]
30#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
31pub struct Quad<S = Term, P = S, O = S, G = S>(pub S, pub P, pub O, pub Option<G>);
32
33impl<S, P, O, G> Quad<S, P, O, G> {
34 #[deprecated(since = "0.18.4", note = "please use `as_ref` instead")]
35 pub fn borrow_components(&self) -> Quad<&S, &P, &O, &G> {
36 self.as_ref()
37 }
38
39 pub fn as_ref(&self) -> Quad<&S, &P, &O, &G> {
41 Quad(&self.0, &self.1, &self.2, self.3.as_ref())
42 }
43}
44
45impl<S, P, O, G> Quad<&S, &P, &O, &G> {
46 pub fn cloned(&self) -> Quad<S, P, O, G>
47 where
48 S: Clone,
49 P: Clone,
50 O: Clone,
51 G: Clone,
52 {
53 Quad(
54 self.0.clone(),
55 self.1.clone(),
56 self.2.clone(),
57 self.3.cloned(),
58 )
59 }
60
61 pub fn into_cloned(self) -> Quad<S, P, O, G>
62 where
63 S: Clone,
64 P: Clone,
65 O: Clone,
66 G: Clone,
67 {
68 Quad(
69 self.0.clone(),
70 self.1.clone(),
71 self.2.clone(),
72 self.3.cloned(),
73 )
74 }
75}
76
77impl<S, P, O, G> Quad<&S, &P, &O, &G> {
78 pub fn copied(&self) -> Quad<S, P, O, G>
79 where
80 S: Copy,
81 P: Copy,
82 O: Copy,
83 G: Copy,
84 {
85 Quad(*self.0, *self.1, *self.2, self.3.copied())
86 }
87
88 pub fn into_copied(self) -> Quad<S, P, O, G>
89 where
90 S: Copy,
91 P: Copy,
92 O: Copy,
93 G: Copy,
94 {
95 Quad(*self.0, *self.1, *self.2, self.3.copied())
96 }
97}
98
99impl LexicalQuad {
100 pub fn as_lexical_quad_ref(&self) -> LexicalQuadRef {
101 Quad(
102 self.0.as_lexical_subject_ref(),
103 self.1.as_iri(),
104 self.2.as_lexical_object_ref(),
105 self.3.as_ref().map(GraphLabel::as_graph_label_ref),
106 )
107 }
108}
109
110impl LexicalQuadRef<'_> {
111 pub fn into_owned(self) -> LexicalQuad {
112 Quad(
113 self.0.into_owned(),
114 self.1.to_owned(),
115 self.2.into_owned(),
116 self.3.map(LexicalGraphLabelRef::into_owned),
117 )
118 }
119}
120
121impl<
122 V,
123 S: EmbedIntoVocabulary<V>,
124 P: EmbedIntoVocabulary<V>,
125 O: EmbedIntoVocabulary<V>,
126 G: EmbedIntoVocabulary<V>,
127 > EmbedIntoVocabulary<V> for Quad<S, P, O, G>
128{
129 type Embedded = Quad<S::Embedded, P::Embedded, O::Embedded, G::Embedded>;
130
131 fn embed_into_vocabulary(self, vocabulary: &mut V) -> Self::Embedded {
132 Quad(
133 self.0.embed_into_vocabulary(vocabulary),
134 self.1.embed_into_vocabulary(vocabulary),
135 self.2.embed_into_vocabulary(vocabulary),
136 self.3.embed_into_vocabulary(vocabulary),
137 )
138 }
139}
140
141impl<
142 V,
143 S: EmbeddedIntoVocabulary<V>,
144 P: EmbeddedIntoVocabulary<V>,
145 O: EmbeddedIntoVocabulary<V>,
146 G: EmbeddedIntoVocabulary<V>,
147 > EmbeddedIntoVocabulary<V> for Quad<S, P, O, G>
148{
149 type Embedded = Quad<S::Embedded, P::Embedded, O::Embedded, G::Embedded>;
150
151 fn embedded_into_vocabulary(&self, vocabulary: &mut V) -> Self::Embedded {
152 Quad(
153 self.0.embedded_into_vocabulary(vocabulary),
154 self.1.embedded_into_vocabulary(vocabulary),
155 self.2.embedded_into_vocabulary(vocabulary),
156 self.3.embedded_into_vocabulary(vocabulary),
157 )
158 }
159}
160
161impl<S, P, O, G> Quad<S, P, O, G> {
162 pub fn new(subject: S, predicate: P, object: O, graph: Option<G>) -> Self {
164 Self(subject, predicate, object, graph)
165 }
166
167 pub fn subject(&self) -> &S {
170 &self.0
171 }
172
173 pub fn subject_mut(&mut self) -> &mut S {
176 &mut self.0
177 }
178
179 pub fn into_subject(self) -> S {
182 self.0
183 }
184
185 pub fn predicate(&self) -> &P {
188 &self.1
189 }
190
191 pub fn predicate_mut(&mut self) -> &mut P {
194 &mut self.1
195 }
196
197 pub fn into_predicate(self) -> P {
200 self.1
201 }
202
203 pub fn object(&self) -> &O {
206 &self.2
207 }
208
209 pub fn object_mut(&mut self) -> &mut O {
212 &mut self.2
213 }
214
215 pub fn into_object(self) -> O {
218 self.2
219 }
220
221 pub fn graph(&self) -> Option<&G> {
224 self.3.as_ref()
225 }
226
227 pub fn graph_mut(&mut self) -> Option<&mut G> {
230 self.3.as_mut()
231 }
232
233 pub fn into_graph(self) -> Option<G> {
236 self.3
237 }
238
239 pub fn into_parts(self) -> (S, P, O, Option<G>) {
240 (self.0, self.1, self.2, self.3)
241 }
242
243 pub fn into_triple(self) -> (Triple<S, P, O>, Option<G>) {
245 (Triple(self.0, self.1, self.2), self.3)
246 }
247
248 pub fn map_subject<U>(self, f: impl FnOnce(S) -> U) -> Quad<U, P, O, G> {
250 Quad(f(self.0), self.1, self.2, self.3)
251 }
252
253 pub fn map_predicate<U>(self, f: impl FnOnce(P) -> U) -> Quad<S, U, O, G> {
255 Quad(self.0, f(self.1), self.2, self.3)
256 }
257
258 pub fn map_object<U>(self, f: impl FnOnce(O) -> U) -> Quad<S, P, U, G> {
260 Quad(self.0, self.1, f(self.2), self.3)
261 }
262
263 pub fn map_graph<U>(self, f: impl FnOnce(Option<G>) -> Option<U>) -> Quad<S, P, O, U> {
265 Quad(self.0, self.1, self.2, f(self.3))
266 }
267
268 pub fn map_all<S2, P2, O2, G2>(
271 self,
272 s: impl FnOnce(S) -> S2,
273 p: impl FnOnce(P) -> P2,
274 o: impl FnOnce(O) -> O2,
275 g: impl FnOnce(Option<G>) -> Option<G2>,
276 ) -> Quad<S2, P2, O2, G2> {
277 Quad(s(self.0), p(self.1), o(self.2), g(self.3))
278 }
279}
280
281impl<T> Quad<T, T, T, T> {
282 pub fn map<U>(self, mut f: impl FnMut(T) -> U) -> Quad<U, U, U, U> {
284 Quad(f(self.0), f(self.1), f(self.2), self.3.map(f))
285 }
286}
287
288impl<S: Interpret<I>, P: Interpret<I>, O: Interpret<I>, G: Interpret<I>, I: Interpretation>
289 Interpret<I> for Quad<S, P, O, G>
290{
291 type Interpreted = Quad<S::Interpreted, P::Interpreted, O::Interpreted, G::Interpreted>;
292
293 fn interpret(self, interpretation: &mut I) -> Self::Interpreted {
294 Quad(
295 self.0.interpret(interpretation),
296 self.1.interpret(interpretation),
297 self.2.interpret(interpretation),
298 self.3.interpret(interpretation),
299 )
300 }
301}
302
303impl<
304 V,
305 S: ExtractFromVocabulary<V>,
306 P: ExtractFromVocabulary<V>,
307 O: ExtractFromVocabulary<V>,
308 G: ExtractFromVocabulary<V>,
309 > ExtractFromVocabulary<V> for Quad<S, P, O, G>
310{
311 type Extracted = Quad<S::Extracted, P::Extracted, O::Extracted, G::Extracted>;
312
313 fn extract_from_vocabulary(self, vocabulary: &V) -> Self::Extracted {
314 Quad(
315 self.0.extract_from_vocabulary(vocabulary),
316 self.1.extract_from_vocabulary(vocabulary),
317 self.2.extract_from_vocabulary(vocabulary),
318 self.3.extract_from_vocabulary(vocabulary),
319 )
320 }
321}
322
323impl<V, S, P, O, G> ExtractFromVocabulary<V> for ByRef<Quad<S, P, O, G>>
324where
325 ByRef<S>: ExtractFromVocabulary<V>,
326 ByRef<P>: ExtractFromVocabulary<V>,
327 ByRef<O>: ExtractFromVocabulary<V>,
328 ByRef<G>: ExtractFromVocabulary<V>,
329{
330 type Extracted = Quad<
331 <ByRef<S> as ExtractFromVocabulary<V>>::Extracted,
332 <ByRef<P> as ExtractFromVocabulary<V>>::Extracted,
333 <ByRef<O> as ExtractFromVocabulary<V>>::Extracted,
334 <ByRef<G> as ExtractFromVocabulary<V>>::Extracted,
335 >;
336
337 fn extract_from_vocabulary(self, vocabulary: &V) -> Self::Extracted {
338 Quad(
339 ByRef(self.0 .0).extract_from_vocabulary(vocabulary),
340 ByRef(self.0 .1).extract_from_vocabulary(vocabulary),
341 ByRef(self.0 .2).extract_from_vocabulary(vocabulary),
342 ByRef(self.0 .3).extract_from_vocabulary(vocabulary),
343 )
344 }
345}
346
347impl<
348 V,
349 S: ExtractedFromVocabulary<V>,
350 P: ExtractedFromVocabulary<V>,
351 O: ExtractedFromVocabulary<V>,
352 G: ExtractedFromVocabulary<V>,
353 > ExtractedFromVocabulary<V> for Quad<S, P, O, G>
354{
355 type Extracted = Quad<S::Extracted, P::Extracted, O::Extracted, G::Extracted>;
356
357 fn extracted_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted {
358 Quad(
359 self.0.extracted_from_vocabulary(vocabulary),
360 self.1.extracted_from_vocabulary(vocabulary),
361 self.2.extracted_from_vocabulary(vocabulary),
362 self.3.extracted_from_vocabulary(vocabulary),
363 )
364 }
365}
366
367pub trait TryExportQuad<S, P, O, G> {
369 type Error;
370
371 fn try_export_quad(&self, quad: Quad<S, P, O, G>) -> Result<LexicalQuad, Self::Error>;
372}
373
374#[derive(Debug, thiserror::Error)]
379pub enum QuadExportFailed<S, P, O, G> {
380 #[error("invalid subject: {0}")]
381 Subject(S),
382
383 #[error("invalid predicate: {0}")]
384 Predicate(P),
385
386 #[error("invalid object: {0}")]
387 Object(O),
388
389 #[error("invalid graph label: {0}")]
390 Graph(G),
391}
392
393impl<
394 V,
395 S: TryExtractFromVocabulary<V>,
396 P: TryExtractFromVocabulary<V>,
397 O: TryExtractFromVocabulary<V>,
398 G: TryExtractFromVocabulary<V>,
399 > TryExtractFromVocabulary<V> for Quad<S, P, O, G>
400{
401 type Extracted = Quad<S::Extracted, P::Extracted, O::Extracted, G::Extracted>;
402 type Error = QuadExportFailed<S::Error, P::Error, O::Error, G::Error>;
403
404 fn try_extract_from_vocabulary(self, vocabulary: &V) -> Result<Self::Extracted, Self::Error> {
405 Ok(Quad(
406 self.0
407 .try_extract_from_vocabulary(vocabulary)
408 .map_err(QuadExportFailed::Subject)?,
409 self.1
410 .try_extract_from_vocabulary(vocabulary)
411 .map_err(QuadExportFailed::Predicate)?,
412 self.2
413 .try_extract_from_vocabulary(vocabulary)
414 .map_err(QuadExportFailed::Object)?,
415 self.3
416 .try_extract_from_vocabulary(vocabulary)
417 .map_err(QuadExportFailed::Graph)?,
418 ))
419 }
420}
421
422impl<
423 S1: PartialEq<S2>,
424 P1: PartialEq<P2>,
425 O1: PartialEq<O2>,
426 G1: PartialEq<G2>,
427 S2,
428 P2,
429 O2,
430 G2,
431 > PartialEq<Quad<S2, P2, O2, G2>> for Quad<S1, P1, O1, G1>
432{
433 fn eq(&self, other: &Quad<S2, P2, O2, G2>) -> bool {
434 self.0 == other.0
435 && self.1 == other.1
436 && self.2 == other.2
437 && match (&self.3, &other.3) {
438 (Some(a), Some(b)) => a == b,
439 (None, None) => true,
440 _ => false,
441 }
442 }
443}
444
445impl<
446 S1: PartialOrd<S2>,
447 P1: PartialOrd<P2>,
448 O1: PartialOrd<O2>,
449 G1: PartialOrd<G2>,
450 S2,
451 P2,
452 O2,
453 G2,
454 > PartialOrd<Quad<S2, P2, O2, G2>> for Quad<S1, P1, O1, G1>
455{
456 fn partial_cmp(&self, other: &Quad<S2, P2, O2, G2>) -> Option<Ordering> {
457 match self.0.partial_cmp(&other.0) {
458 Some(Ordering::Equal) => match self.1.partial_cmp(&other.1) {
459 Some(Ordering::Equal) => match self.2.partial_cmp(&other.2) {
460 Some(Ordering::Equal) => match (&self.3, &other.3) {
461 (Some(a), Some(b)) => a.partial_cmp(b),
462 (Some(_), None) => Some(Ordering::Greater),
463 (None, Some(_)) => Some(Ordering::Less),
464 (None, None) => Some(Ordering::Equal),
465 },
466 cmp => cmp,
467 },
468 cmp => cmp,
469 },
470 cmp => cmp,
471 }
472 }
473}
474
475impl<S: RdfDisplay, P: RdfDisplay, O: RdfDisplay, G: RdfDisplay> fmt::Display for Quad<S, P, O, G> {
476 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
477 match self.graph() {
478 Some(graph) => write!(
479 f,
480 "{} {} {} {}",
481 self.0.rdf_display(),
482 self.1.rdf_display(),
483 self.2.rdf_display(),
484 graph.rdf_display()
485 ),
486 None => write!(
487 f,
488 "{} {} {}",
489 self.0.rdf_display(),
490 self.1.rdf_display(),
491 self.2.rdf_display()
492 ),
493 }
494 }
495}
496
497impl<S: RdfDisplay, P: RdfDisplay, O: RdfDisplay, G: RdfDisplay> RdfDisplay for Quad<S, P, O, G> {
498 fn rdf_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
499 match self.graph() {
500 Some(graph) => write!(
501 f,
502 "{} {} {} {}",
503 self.0.rdf_display(),
504 self.1.rdf_display(),
505 self.2.rdf_display(),
506 graph.rdf_display()
507 ),
508 None => write!(
509 f,
510 "{} {} {}",
511 self.0.rdf_display(),
512 self.1.rdf_display(),
513 self.2.rdf_display()
514 ),
515 }
516 }
517}
518
519#[cfg(feature = "contextual")]
520impl<
521 S: RdfDisplayWithContext<V>,
522 P: RdfDisplayWithContext<V>,
523 O: RdfDisplayWithContext<V>,
524 G: RdfDisplayWithContext<V>,
525 V,
526 > DisplayWithContext<V> for Quad<S, P, O, G>
527{
528 fn fmt_with(&self, vocabulary: &V, f: &mut fmt::Formatter) -> fmt::Result {
529 match self.graph() {
530 Some(graph) => write!(
531 f,
532 "{} {} {} {}",
533 self.0.with(vocabulary).rdf_display(),
534 self.1.with(vocabulary).rdf_display(),
535 self.2.with(vocabulary).rdf_display(),
536 graph.with(vocabulary).rdf_display()
537 ),
538 None => write!(
539 f,
540 "{} {} {}",
541 self.0.with(vocabulary).rdf_display(),
542 self.1.with(vocabulary).rdf_display(),
543 self.2.with(vocabulary).rdf_display()
544 ),
545 }
546 }
547}
548
549#[cfg(feature = "contextual")]
550impl<
551 S: RdfDisplayWithContext<V>,
552 P: RdfDisplayWithContext<V>,
553 O: RdfDisplayWithContext<V>,
554 G: RdfDisplayWithContext<V>,
555 V,
556 > RdfDisplayWithContext<V> for Quad<S, P, O, G>
557{
558 fn rdf_fmt_with(&self, vocabulary: &V, f: &mut fmt::Formatter) -> fmt::Result {
559 match self.graph() {
560 Some(graph) => write!(
561 f,
562 "{} {} {} {}",
563 self.0.with(vocabulary).rdf_display(),
564 self.1.with(vocabulary).rdf_display(),
565 self.2.with(vocabulary).rdf_display(),
566 graph.with(vocabulary).rdf_display()
567 ),
568 None => write!(
569 f,
570 "{} {} {}",
571 self.0.with(vocabulary).rdf_display(),
572 self.1.with(vocabulary).rdf_display(),
573 self.2.with(vocabulary).rdf_display()
574 ),
575 }
576 }
577}