1use crate::model::star::QuotedTriple;
4use crate::model::RdfTerm;
5use crate::model::{BlankNode, Literal, NamedNode, Object, Predicate, Subject, Variable};
6use serde::{Deserialize, Serialize};
7use std::fmt;
8use std::hash::Hash;
9
10#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
44pub struct Triple {
45 subject: Subject,
46 predicate: Predicate,
47 object: Object,
48}
49
50impl Triple {
51 pub fn new(
86 subject: impl Into<Subject>,
87 predicate: impl Into<Predicate>,
88 object: impl Into<Object>,
89 ) -> Self {
90 Triple {
91 subject: subject.into(),
92 predicate: predicate.into(),
93 object: object.into(),
94 }
95 }
96
97 pub fn as_ref(&self) -> TripleRef<'_> {
99 TripleRef::from(self)
100 }
101
102 pub fn subject(&self) -> &Subject {
104 &self.subject
105 }
106
107 pub fn predicate(&self) -> &Predicate {
109 &self.predicate
110 }
111
112 pub fn object(&self) -> &Object {
114 &self.object
115 }
116
117 pub fn into_parts(self) -> (Subject, Predicate, Object) {
119 (self.subject, self.predicate, self.object)
120 }
121
122 pub fn has_variables(&self) -> bool {
124 matches!(self.subject, Subject::Variable(_))
125 || matches!(self.predicate, Predicate::Variable(_))
126 || matches!(self.object, Object::Variable(_))
127 }
128
129 pub fn is_ground(&self) -> bool {
131 !self.has_variables()
132 }
133
134 pub fn matches_pattern(
138 &self,
139 subject: Option<&Subject>,
140 predicate: Option<&Predicate>,
141 object: Option<&Object>,
142 ) -> bool {
143 if let Some(s) = subject {
144 if &self.subject != s {
145 return false;
146 }
147 }
148
149 if let Some(p) = predicate {
150 if &self.predicate != p {
151 return false;
152 }
153 }
154
155 if let Some(o) = object {
156 if &self.object != o {
157 return false;
158 }
159 }
160
161 true
162 }
163
164 #[allow(dead_code)]
169 fn canonical_ordering(&self) -> (u8, &str, u8, &str, u8, &str) {
170 let subject_ord = match &self.subject {
171 Subject::NamedNode(_) => 0,
172 Subject::BlankNode(_) => 1,
173 Subject::Variable(_) => 2,
174 Subject::QuotedTriple(_) => 3,
175 };
176
177 let predicate_ord = match &self.predicate {
178 Predicate::NamedNode(_) => 0,
179 Predicate::Variable(_) => 1,
180 };
181
182 let object_ord = match &self.object {
183 Object::NamedNode(_) => 0,
184 Object::BlankNode(_) => 1,
185 Object::Literal(_) => 2,
186 Object::Variable(_) => 3,
187 Object::QuotedTriple(_) => 4,
188 };
189
190 (
191 subject_ord,
192 self.subject_str(),
193 predicate_ord,
194 self.predicate_str(),
195 object_ord,
196 self.object_str(),
197 )
198 }
199
200 #[allow(dead_code)]
202 fn subject_str(&self) -> &str {
203 match &self.subject {
204 Subject::NamedNode(n) => n.as_str(),
205 Subject::BlankNode(b) => b.as_str(),
206 Subject::Variable(v) => v.as_str(),
207 Subject::QuotedTriple(_) => "<<quoted-triple>>",
208 }
209 }
210
211 #[allow(dead_code)]
213 fn predicate_str(&self) -> &str {
214 match &self.predicate {
215 Predicate::NamedNode(n) => n.as_str(),
216 Predicate::Variable(v) => v.as_str(),
217 }
218 }
219
220 #[allow(dead_code)]
222 fn object_str(&self) -> &str {
223 match &self.object {
224 Object::NamedNode(n) => n.as_str(),
225 Object::BlankNode(b) => b.as_str(),
226 Object::Literal(l) => l.as_str(),
227 Object::Variable(v) => v.as_str(),
228 Object::QuotedTriple(_) => "<<quoted-triple>>",
229 }
230 }
231}
232
233impl fmt::Display for Triple {
234 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
235 write!(f, "{} {} {} .", self.subject, self.predicate, self.object)
236 }
237}
238
239impl fmt::Display for Subject {
241 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242 match self {
243 Subject::NamedNode(n) => write!(f, "{n}"),
244 Subject::BlankNode(b) => write!(f, "{b}"),
245 Subject::Variable(v) => write!(f, "{v}"),
246 Subject::QuotedTriple(qt) => write!(f, "{qt}"),
247 }
248 }
249}
250
251impl fmt::Display for Predicate {
252 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
253 match self {
254 Predicate::NamedNode(n) => write!(f, "{n}"),
255 Predicate::Variable(v) => write!(f, "{v}"),
256 }
257 }
258}
259
260impl fmt::Display for Object {
261 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
262 match self {
263 Object::NamedNode(n) => write!(f, "{n}"),
264 Object::BlankNode(b) => write!(f, "{b}"),
265 Object::Literal(l) => write!(f, "{l}"),
266 Object::Variable(v) => write!(f, "{v}"),
267 Object::QuotedTriple(qt) => write!(f, "{qt}"),
268 }
269 }
270}
271
272#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
274pub struct TripleRef<'a> {
275 subject: SubjectRef<'a>,
276 predicate: PredicateRef<'a>,
277 object: ObjectRef<'a>,
278}
279
280impl<'a> TripleRef<'a> {
281 pub fn new(
283 subject: SubjectRef<'a>,
284 predicate: PredicateRef<'a>,
285 object: ObjectRef<'a>,
286 ) -> Self {
287 TripleRef {
288 subject,
289 predicate,
290 object,
291 }
292 }
293
294 pub fn subject(&self) -> SubjectRef<'a> {
296 self.subject
297 }
298
299 pub fn predicate(&self) -> PredicateRef<'a> {
301 self.predicate
302 }
303
304 pub fn object(&self) -> ObjectRef<'a> {
306 self.object
307 }
308
309 pub fn to_owned(&self) -> Triple {
311 Triple {
312 subject: self.subject.to_owned(),
313 predicate: self.predicate.to_owned(),
314 object: self.object.to_owned(),
315 }
316 }
317
318 pub fn into_owned(self) -> Triple {
320 self.to_owned()
321 }
322
323 pub fn in_graph(
325 self,
326 graph_name: Option<&'a crate::model::NamedNode>,
327 ) -> crate::model::QuadRef<'a> {
328 let graph_ref = match graph_name {
329 Some(node) => crate::model::GraphNameRef::NamedNode(node),
330 None => crate::model::GraphNameRef::DefaultGraph,
331 };
332 crate::model::QuadRef::new(self.subject, self.predicate, self.object, graph_ref)
333 }
334}
335
336impl<'a> fmt::Display for TripleRef<'a> {
337 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
338 write!(f, "{} {} {} .", self.subject, self.predicate, self.object)
339 }
340}
341
342#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
344pub enum SubjectRef<'a> {
345 NamedNode(&'a NamedNode),
346 BlankNode(&'a BlankNode),
347 Variable(&'a Variable),
348 QuotedTriple(&'a QuotedTriple),
350}
351
352impl<'a> SubjectRef<'a> {
353 pub fn to_owned(&self) -> Subject {
355 match self {
356 SubjectRef::NamedNode(n) => Subject::NamedNode((*n).clone()),
357 SubjectRef::BlankNode(b) => Subject::BlankNode((*b).clone()),
358 SubjectRef::Variable(v) => Subject::Variable((*v).clone()),
359 SubjectRef::QuotedTriple(qt) => Subject::QuotedTriple(Box::new((*qt).clone())),
360 }
361 }
362}
363
364impl<'a> fmt::Display for SubjectRef<'a> {
365 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
366 match self {
367 SubjectRef::NamedNode(n) => write!(f, "{n}"),
368 SubjectRef::BlankNode(b) => write!(f, "{b}"),
369 SubjectRef::Variable(v) => write!(f, "{v}"),
370 SubjectRef::QuotedTriple(qt) => write!(f, "{qt}"),
371 }
372 }
373}
374
375#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
377pub enum PredicateRef<'a> {
378 NamedNode(&'a NamedNode),
379 Variable(&'a Variable),
380}
381
382impl<'a> PredicateRef<'a> {
383 pub fn to_owned(&self) -> Predicate {
385 match self {
386 PredicateRef::NamedNode(n) => Predicate::NamedNode((*n).clone()),
387 PredicateRef::Variable(v) => Predicate::Variable((*v).clone()),
388 }
389 }
390}
391
392impl<'a> fmt::Display for PredicateRef<'a> {
393 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
394 match self {
395 PredicateRef::NamedNode(n) => write!(f, "{n}"),
396 PredicateRef::Variable(v) => write!(f, "{v}"),
397 }
398 }
399}
400
401#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
403pub enum ObjectRef<'a> {
404 NamedNode(&'a NamedNode),
405 BlankNode(&'a BlankNode),
406 Literal(&'a Literal),
407 Variable(&'a Variable),
408 QuotedTriple(&'a QuotedTriple),
410}
411
412impl<'a> ObjectRef<'a> {
413 pub fn to_owned(&self) -> Object {
415 match self {
416 ObjectRef::NamedNode(n) => Object::NamedNode((*n).clone()),
417 ObjectRef::BlankNode(b) => Object::BlankNode((*b).clone()),
418 ObjectRef::Literal(l) => Object::Literal((*l).clone()),
419 ObjectRef::Variable(v) => Object::Variable((*v).clone()),
420 ObjectRef::QuotedTriple(qt) => Object::QuotedTriple(Box::new((*qt).clone())),
421 }
422 }
423}
424
425impl<'a> fmt::Display for ObjectRef<'a> {
426 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
427 match self {
428 ObjectRef::NamedNode(n) => write!(f, "{n}"),
429 ObjectRef::BlankNode(b) => write!(f, "{b}"),
430 ObjectRef::Literal(l) => write!(f, "{l}"),
431 ObjectRef::Variable(v) => write!(f, "{v}"),
432 ObjectRef::QuotedTriple(qt) => write!(f, "{qt}"),
433 }
434 }
435}
436
437impl<'a> From<&'a Subject> for SubjectRef<'a> {
439 fn from(subject: &'a Subject) -> Self {
440 match subject {
441 Subject::NamedNode(n) => SubjectRef::NamedNode(n),
442 Subject::BlankNode(b) => SubjectRef::BlankNode(b),
443 Subject::Variable(v) => SubjectRef::Variable(v),
444 Subject::QuotedTriple(qt) => SubjectRef::QuotedTriple(qt),
445 }
446 }
447}
448
449impl<'a> From<&'a Predicate> for PredicateRef<'a> {
450 fn from(predicate: &'a Predicate) -> Self {
451 match predicate {
452 Predicate::NamedNode(n) => PredicateRef::NamedNode(n),
453 Predicate::Variable(v) => PredicateRef::Variable(v),
454 }
455 }
456}
457
458impl<'a> From<&'a Object> for ObjectRef<'a> {
459 fn from(object: &'a Object) -> Self {
460 match object {
461 Object::NamedNode(n) => ObjectRef::NamedNode(n),
462 Object::BlankNode(b) => ObjectRef::BlankNode(b),
463 Object::Literal(l) => ObjectRef::Literal(l),
464 Object::Variable(v) => ObjectRef::Variable(v),
465 Object::QuotedTriple(qt) => ObjectRef::QuotedTriple(qt),
466 }
467 }
468}
469
470impl<'a> From<&'a Triple> for TripleRef<'a> {
471 fn from(triple: &'a Triple) -> Self {
472 TripleRef {
473 subject: triple.subject().into(),
474 predicate: triple.predicate().into(),
475 object: triple.object().into(),
476 }
477 }
478}
479
480impl<'a> From<TripleRef<'a>> for Triple {
481 fn from(triple_ref: TripleRef<'a>) -> Self {
482 triple_ref.to_owned()
483 }
484}
485
486#[cfg(test)]
487mod tests {
488 use super::*;
489 use crate::model::{Literal, NamedNode};
490
491 #[test]
492 fn test_triple_creation() {
493 let subject = NamedNode::new("http://example.org/subject").expect("valid IRI");
494 let predicate = NamedNode::new("http://example.org/predicate").expect("valid IRI");
495 let object = Literal::new("object");
496
497 let triple = Triple::new(subject.clone(), predicate.clone(), object.clone());
498
499 assert!(triple.is_ground());
500 assert!(!triple.has_variables());
501 }
502
503 #[test]
504 fn test_triple_with_variable() {
505 let subject = Variable::new("x").expect("valid variable name");
506 let predicate = NamedNode::new("http://example.org/predicate").expect("valid IRI");
507 let object = Literal::new("object");
508
509 let triple = Triple::new(subject, predicate, object);
510
511 assert!(!triple.is_ground());
512 assert!(triple.has_variables());
513 }
514
515 #[test]
516 fn test_triple_display() {
517 let subject = NamedNode::new("http://example.org/s").expect("valid IRI");
518 let predicate = NamedNode::new("http://example.org/p").expect("valid IRI");
519 let object = Literal::new("o");
520
521 let triple = Triple::new(subject, predicate, object);
522 let display_str = format!("{triple}");
523
524 assert!(display_str.contains("http://example.org/s"));
525 assert!(display_str.contains("http://example.org/p"));
526 assert!(display_str.contains("\"o\""));
527 assert!(display_str.ends_with(" ."));
528 }
529
530 #[test]
531 fn test_triple_ref() {
532 let subject = NamedNode::new("http://example.org/s").expect("valid IRI");
533 let predicate = NamedNode::new("http://example.org/p").expect("valid IRI");
534 let object = Literal::new("o");
535
536 let triple = Triple::new(subject, predicate, object);
537 let triple_ref = TripleRef::from(&triple);
538 let triple_owned = triple_ref.to_owned();
539
540 assert_eq!(triple, triple_owned);
541 }
542
543 #[test]
544 fn test_pattern_matching() {
545 let subject = NamedNode::new("http://example.org/s").expect("valid IRI");
546 let predicate = NamedNode::new("http://example.org/p").expect("valid IRI");
547 let object = Literal::new("o");
548
549 let triple = Triple::new(subject.clone(), predicate.clone(), object.clone());
550
551 assert!(triple.matches_pattern(
553 Some(&Subject::NamedNode(subject.clone())),
554 Some(&Predicate::NamedNode(predicate.clone())),
555 Some(&Object::Literal(object.clone()))
556 ));
557
558 assert!(triple.matches_pattern(None, None, None));
560 assert!(triple.matches_pattern(Some(&Subject::NamedNode(subject.clone())), None, None));
561 assert!(triple.matches_pattern(None, Some(&Predicate::NamedNode(predicate.clone())), None));
562 assert!(triple.matches_pattern(None, None, Some(&Object::Literal(object.clone()))));
563
564 let different_subject = NamedNode::new("http://example.org/different").expect("valid IRI");
566 assert!(!triple.matches_pattern(Some(&Subject::NamedNode(different_subject)), None, None));
567 }
568
569 #[test]
570 fn test_triple_ordering() {
571 let subject1 = NamedNode::new("http://example.org/a").expect("valid IRI");
572 let subject2 = NamedNode::new("http://example.org/b").expect("valid IRI");
573 let predicate = NamedNode::new("http://example.org/p").expect("valid IRI");
574 let object = Literal::new("o");
575
576 let triple1 = Triple::new(subject1, predicate.clone(), object.clone());
577 let triple2 = Triple::new(subject2, predicate, object);
578
579 assert!(triple1 < triple2);
580
581 let mut triples = vec![triple2.clone(), triple1.clone()];
582 triples.sort();
583 assert_eq!(triples, vec![triple1, triple2]);
584 }
585
586 #[test]
587 fn regression_rdf_star_as_ref_does_not_panic() {
588 use crate::model::star::QuotedTriple;
589
590 let inner = Triple::new(
592 NamedNode::new("http://example.org/s").expect("valid IRI"),
593 NamedNode::new("http://example.org/p").expect("valid IRI"),
594 Literal::new("o"),
595 );
596 let qt = QuotedTriple::new(inner);
597 let outer = Triple::new(
598 Subject::QuotedTriple(Box::new(qt.clone())),
599 NamedNode::new("http://example.org/asserts").expect("valid IRI"),
600 Object::QuotedTriple(Box::new(qt)),
601 );
602
603 let borrowed = outer.as_ref();
605 assert!(matches!(borrowed.subject(), SubjectRef::QuotedTriple(_)));
606 assert!(matches!(borrowed.object(), ObjectRef::QuotedTriple(_)));
607
608 let round = borrowed.to_owned();
610 assert_eq!(outer, round);
611
612 let rendered = format!("{}", borrowed.subject());
614 assert!(rendered.contains("<<"));
615 assert!(rendered.contains("http://example.org/s"));
616 }
617
618 #[test]
619 fn test_triple_serialization() {
620 let subject = NamedNode::new("http://example.org/s").expect("valid IRI");
621 let predicate = NamedNode::new("http://example.org/p").expect("valid IRI");
622 let object = Literal::new("o");
623
624 let triple = Triple::new(subject, predicate, object);
625 let json = serde_json::to_string(&triple).expect("construction should succeed");
626 let deserialized: Triple =
627 serde_json::from_str(&json).expect("construction should succeed");
628
629 assert_eq!(triple, deserialized);
630 }
631}