sophia_rio/
model.rs

1//! Implement Sophia traits for types defined in Rio.
2//!
3//! NB: since [`rio_api::model`] types have public fields,
4//! they can not in general be trusted to contain valid data
5//! (e.g. a valid IRI in [`NamedNode`]).
6//!
7//! However, their typical use-case is to be produced by a parser,
8//! which ensures the validity of the underlying data.
9//!
10//! The [`Trusted`] wrapper is used to materialize the fact that we trust the underlying data of Rio types.
11use rio_api::model::{Quad as RioQuad, Term as RioTerm, Triple as RioTriple, *};
12use sophia_api::ns::{rdf, xsd};
13use sophia_api::quad::{QBorrowTerm, Quad, Spog};
14use sophia_api::term::{BnodeId, LanguageTag, Term, TermKind, VarName};
15use sophia_api::triple::{TBorrowTerm, Triple};
16use sophia_api::MownStr;
17use sophia_iri::{Iri, IriRef};
18
19impl<'a> Term for Trusted<BlankNode<'a>> {
20    type BorrowTerm<'x> = Self where Self: 'x;
21
22    fn kind(&self) -> TermKind {
23        TermKind::BlankNode
24    }
25
26    fn bnode_id(&self) -> Option<BnodeId<MownStr>> {
27        Some(bnode_id(self.0))
28    }
29
30    fn borrow_term(&self) -> Self::BorrowTerm<'_> {
31        *self
32    }
33}
34
35fn bnode_id(b: BlankNode) -> BnodeId<MownStr> {
36    debug_assert!(BnodeId::new(b.id).is_ok());
37    BnodeId::new_unchecked(b.id.into())
38}
39
40impl<'a> Term for Trusted<NamedNode<'a>> {
41    type BorrowTerm<'x> = Self where Self: 'x;
42
43    fn kind(&self) -> TermKind {
44        TermKind::Iri
45    }
46
47    fn iri(&self) -> Option<sophia_iri::IriRef<MownStr<'_>>> {
48        Some(iri(self.0))
49    }
50
51    fn borrow_term(&self) -> Self::BorrowTerm<'_> {
52        *self
53    }
54}
55
56fn iri(n: NamedNode) -> IriRef<MownStr> {
57    debug_assert!(IriRef::new(n.iri).is_ok());
58    IriRef::new_unchecked(n.iri.into())
59}
60
61impl<'a> Term for Trusted<Variable<'a>> {
62    type BorrowTerm<'x> = Self where Self: 'x;
63
64    fn kind(&self) -> TermKind {
65        TermKind::Variable
66    }
67
68    fn variable(&self) -> Option<VarName<MownStr>> {
69        Some(variable(self.0))
70    }
71
72    fn borrow_term(&self) -> Self::BorrowTerm<'_> {
73        *self
74    }
75}
76
77fn variable(v: Variable) -> VarName<MownStr> {
78    debug_assert!(VarName::new(v.name).is_ok());
79    VarName::new_unchecked(v.name.into())
80}
81
82impl<'a> Term for Trusted<Literal<'a>> {
83    type BorrowTerm<'x> = Self where Self: 'x;
84
85    fn kind(&self) -> TermKind {
86        TermKind::Literal
87    }
88
89    fn lexical_form(&self) -> Option<MownStr> {
90        Some(lexical_form(self.0))
91    }
92
93    fn datatype(&self) -> Option<IriRef<MownStr>> {
94        Some(datatype(self.0))
95    }
96
97    fn language_tag(&self) -> Option<LanguageTag<MownStr>> {
98        language_tag(self.0)
99    }
100
101    fn borrow_term(&self) -> Self::BorrowTerm<'_> {
102        *self
103    }
104}
105
106fn lexical_form(l: Literal) -> MownStr {
107    use Literal::*;
108    let value = match l {
109        Simple { value } => value,
110        LanguageTaggedString { value, .. } => value,
111        Typed { value, .. } => value,
112    };
113    value.into()
114}
115
116fn datatype(l: Literal) -> IriRef<MownStr> {
117    use Literal::*;
118    let dt = match l {
119        Simple { .. } => xsd::string.iriref(),
120        LanguageTaggedString { .. } => rdf::langString.iriref(),
121        Typed { datatype, .. } => {
122            debug_assert!(Iri::new(datatype.iri).is_ok());
123            IriRef::new_unchecked(datatype.iri.into())
124        }
125    };
126    dt
127}
128
129fn language_tag(l: Literal) -> Option<LanguageTag<MownStr>> {
130    if let Literal::LanguageTaggedString { language, .. } = l {
131        debug_assert!(LanguageTag::new(language).is_ok());
132        Some(LanguageTag::new_unchecked(language.into()))
133    } else {
134        None
135    }
136}
137
138/*  // NB: rio::Subject can not fully implement sophia::Term,
139    // because the subterms of embedded triples might be literals
140
141    // However, this is not required for interfacing with Sophia;
142    // we cheat by forcing RioTriple to expose its subject as a RioTerm.
143
144impl<'a> Term for Trusted<Subject<'a>> {
145    type BorrowTerm<'x>
146    where
147        Self: 'x,
148    = Trusted<RioTerm<'a>>;
149
150    fn kind(&self) -> TermKind {
151        use Subject::*;
152        match self.0 {
153            NamedNode(_) => TermKind::Iri,
154            BlankNode(_) => TermKind::BlankNode,
155            Triple(_) => TermKind::Triple,
156        }
157    }
158
159    fn iri(&self) -> Option<IriRef<MownStr<'_>>> {
160        if let Subject::NamedNode(n) = self.0 {
161            Some(iri(n))
162        } else {
163            None
164        }
165    }
166
167    fn bnode_id(&self) -> Option<BnodeId<MownStr>> {
168        if let Subject::BlankNode(b) = self.0 {
169            Some(bnode_id(b))
170        } else {
171            None
172        }
173    }
174
175    fn triple(&self) -> Option<[Self::BorrowTerm<'_>; 3]> {
176        if let Subject::Triple(t) = self.0 {
177            let s = Trusted(t.subject.into());
178            let p = Trusted(t.predicate.into());
179            let o = Trusted(t.object);
180            Some([s, p, o])
181        } else {
182            None
183        }
184    }
185
186    fn to_triple(self) -> Option<[Self; 3]>
187    where
188        Self: Sized,
189    {
190        if let Subject::Triple(_) = self.0 {
191            // there is an impedence mismatch between Sophia and Rio:
192            // we can not convert a triple into [Subject; 3]
193            unimplemented!()
194        } else {
195            None
196        }
197    }
198
199    fn borrow_term(&self) -> Self::BorrowTerm<'_> {
200        Trusted(self.0.into())
201    }
202}
203*/
204
205impl<'a> Term for Trusted<GraphName<'a>> {
206    type BorrowTerm<'x> = Self where Self: 'x;
207
208    fn kind(&self) -> TermKind {
209        use GraphName::*;
210        match self.0 {
211            NamedNode(_) => TermKind::Iri,
212            BlankNode(_) => TermKind::BlankNode,
213        }
214    }
215
216    fn iri(&self) -> Option<IriRef<MownStr<'_>>> {
217        if let GraphName::NamedNode(n) = self.0 {
218            Some(iri(n))
219        } else {
220            None
221        }
222    }
223
224    fn bnode_id(&self) -> Option<BnodeId<MownStr>> {
225        if let GraphName::BlankNode(b) = self.0 {
226            Some(bnode_id(b))
227        } else {
228            None
229        }
230    }
231
232    fn borrow_term(&self) -> Self::BorrowTerm<'_> {
233        Trusted(self.0)
234    }
235}
236
237impl<'a> Term for Trusted<RioTerm<'a>> {
238    type BorrowTerm<'x> = Self where Self: 'x;
239
240    fn kind(&self) -> TermKind {
241        use RioTerm::*;
242        match self.0 {
243            NamedNode(_) => TermKind::Iri,
244            BlankNode(_) => TermKind::BlankNode,
245            Literal(_) => TermKind::Literal,
246            Triple(_) => TermKind::Triple,
247        }
248    }
249
250    fn iri(&self) -> Option<IriRef<MownStr>> {
251        if let RioTerm::NamedNode(n) = self.0 {
252            Some(iri(n))
253        } else {
254            None
255        }
256    }
257
258    fn bnode_id(&self) -> Option<BnodeId<MownStr>> {
259        if let RioTerm::BlankNode(b) = self.0 {
260            Some(bnode_id(b))
261        } else {
262            None
263        }
264    }
265
266    fn lexical_form(&self) -> Option<MownStr> {
267        if let RioTerm::Literal(l) = self.0 {
268            Some(lexical_form(l))
269        } else {
270            None
271        }
272    }
273
274    fn datatype(&self) -> Option<IriRef<MownStr>> {
275        if let RioTerm::Literal(l) = self.0 {
276            Some(datatype(l))
277        } else {
278            None
279        }
280    }
281
282    fn language_tag(&self) -> Option<LanguageTag<MownStr>> {
283        if let RioTerm::Literal(l) = self.0 {
284            language_tag(l)
285        } else {
286            None
287        }
288    }
289
290    fn triple(&self) -> Option<[Self::BorrowTerm<'_>; 3]> {
291        self.to_triple()
292    }
293
294    fn to_triple(self) -> Option<[Self; 3]>
295    where
296        Self: Sized,
297    {
298        if let RioTerm::Triple(t) = self.0 {
299            let s = Trusted(t.subject.into());
300            let p = Trusted(t.predicate.into());
301            let o = Trusted(t.object);
302            Some([s, p, o])
303        } else {
304            None
305        }
306    }
307
308    fn borrow_term(&self) -> Self::BorrowTerm<'_> {
309        *self
310    }
311}
312
313impl<'a> Term for Trusted<GeneralizedTerm<'a>> {
314    type BorrowTerm<'x> = Self where Self: 'x;
315
316    fn kind(&self) -> TermKind {
317        use GeneralizedTerm::*;
318        match self.0 {
319            NamedNode(_) => TermKind::Iri,
320            BlankNode(_) => TermKind::BlankNode,
321            Literal(_) => TermKind::Literal,
322            Triple(_) => TermKind::Triple,
323            Variable(_) => TermKind::Variable,
324        }
325    }
326
327    fn iri(&self) -> Option<IriRef<MownStr>> {
328        if let GeneralizedTerm::NamedNode(n) = self.0 {
329            Some(iri(n))
330        } else {
331            None
332        }
333    }
334
335    fn bnode_id(&self) -> Option<BnodeId<MownStr>> {
336        if let GeneralizedTerm::BlankNode(b) = self.0 {
337            Some(bnode_id(b))
338        } else {
339            None
340        }
341    }
342
343    fn lexical_form(&self) -> Option<MownStr> {
344        if let GeneralizedTerm::Literal(l) = self.0 {
345            Some(lexical_form(l))
346        } else {
347            None
348        }
349    }
350
351    fn datatype(&self) -> Option<IriRef<MownStr>> {
352        if let GeneralizedTerm::Literal(l) = self.0 {
353            Some(datatype(l))
354        } else {
355            None
356        }
357    }
358
359    fn language_tag(&self) -> Option<LanguageTag<MownStr>> {
360        if let GeneralizedTerm::Literal(l) = self.0 {
361            language_tag(l)
362        } else {
363            None
364        }
365    }
366
367    fn triple(&self) -> Option<[Self::BorrowTerm<'_>; 3]> {
368        self.to_triple()
369    }
370
371    fn to_triple(self) -> Option<[Self; 3]>
372    where
373        Self: Sized,
374    {
375        if let GeneralizedTerm::Triple(t) = self.0 {
376            let s = Trusted(t[0]);
377            let p = Trusted(t[1]);
378            let o = Trusted(t[2]);
379            Some([s, p, o])
380        } else {
381            None
382        }
383    }
384
385    fn variable(&self) -> Option<VarName<MownStr>> {
386        if let GeneralizedTerm::Variable(v) = self.0 {
387            Some(variable(v))
388        } else {
389            None
390        }
391    }
392
393    fn borrow_term(&self) -> Self::BorrowTerm<'_> {
394        *self
395    }
396}
397
398impl<'a> Triple for Trusted<RioTriple<'a>> {
399    type Term = Trusted<RioTerm<'a>>;
400
401    fn s(&self) -> TBorrowTerm<Self> {
402        Trusted(self.subject.into())
403    }
404
405    fn p(&self) -> TBorrowTerm<Self> {
406        Trusted(self.predicate.into())
407    }
408
409    fn o(&self) -> TBorrowTerm<Self> {
410        Trusted(self.object)
411    }
412
413    fn to_s(self) -> Self::Term {
414        Trusted(self.subject.into())
415    }
416
417    fn to_p(self) -> Self::Term {
418        Trusted(self.predicate.into())
419    }
420
421    fn to_o(self) -> Self::Term {
422        Trusted(self.object)
423    }
424
425    fn to_spo(self) -> [Self::Term; 3] {
426        [self.to_s(), self.to_p(), self.to_o()]
427    }
428}
429
430impl<'a> Quad for Trusted<RioQuad<'a>> {
431    type Term = Trusted<RioTerm<'a>>;
432
433    fn s(&self) -> QBorrowTerm<Self> {
434        Trusted(self.subject.into())
435    }
436
437    fn p(&self) -> QBorrowTerm<Self> {
438        Trusted(self.predicate.into())
439    }
440
441    fn o(&self) -> QBorrowTerm<Self> {
442        Trusted(self.object)
443    }
444
445    fn g(&self) -> Option<QBorrowTerm<Self>> {
446        self.graph_name.map(|g| Trusted(g.into()))
447    }
448
449    fn to_s(self) -> Self::Term {
450        Trusted(self.subject.into())
451    }
452
453    fn to_p(self) -> Self::Term {
454        Trusted(self.predicate.into())
455    }
456
457    fn to_o(self) -> Self::Term {
458        Trusted(self.object)
459    }
460
461    fn to_g(self) -> Option<Self::Term> {
462        self.graph_name.map(|g| Trusted(g.into()))
463    }
464
465    fn to_spog(self) -> Spog<Self::Term> {
466        ([self.to_s(), self.to_p(), self.to_o()], self.to_g())
467    }
468}
469
470impl<'a> Quad for Trusted<GeneralizedQuad<'a>> {
471    type Term = Trusted<GeneralizedTerm<'a>>;
472
473    fn s(&self) -> QBorrowTerm<Self> {
474        Trusted(self.subject)
475    }
476
477    fn p(&self) -> QBorrowTerm<Self> {
478        Trusted(self.predicate)
479    }
480
481    fn o(&self) -> QBorrowTerm<Self> {
482        Trusted(self.object)
483    }
484
485    fn g(&self) -> Option<QBorrowTerm<Self>> {
486        self.graph_name.map(Trusted)
487    }
488
489    fn to_s(self) -> Self::Term {
490        Trusted(self.subject)
491    }
492
493    fn to_p(self) -> Self::Term {
494        Trusted(self.predicate)
495    }
496
497    fn to_o(self) -> Self::Term {
498        Trusted(self.object)
499    }
500
501    fn to_g(self) -> Option<Self::Term> {
502        self.graph_name.map(Trusted)
503    }
504
505    fn to_spog(self) -> Spog<Self::Term> {
506        ([self.s(), self.p(), self.o()], self.g())
507    }
508}
509
510/// A wrapper for Rio types that are trusted to contain valid data
511#[derive(Clone, Copy, Debug)]
512pub struct Trusted<T>(pub T);
513
514impl<T> std::ops::Deref for Trusted<T> {
515    type Target = T;
516
517    fn deref(&self) -> &Self::Target {
518        &self.0
519    }
520}
521
522#[cfg(test)]
523mod test {
524    use super::*;
525    use sophia_api::term::assert_consistent_term_impl;
526
527    #[test]
528    fn blank_node() {
529        assert_consistent_term_impl(&Trusted(BlankNode { id: "foo" }))
530    }
531
532    #[test]
533    fn named_node() {
534        assert_consistent_term_impl(&Trusted(NamedNode { iri: "tag:foo" }));
535    }
536
537    #[test]
538    fn variable() {
539        assert_consistent_term_impl(&Trusted(Variable { name: "foo" }));
540    }
541
542    #[test]
543    fn literal_simple() {
544        assert_consistent_term_impl(&Trusted(Literal::Simple { value: "foo" }));
545    }
546
547    #[test]
548    fn literal_language() {
549        assert_consistent_term_impl(&Trusted(Literal::LanguageTaggedString {
550            value: "foo",
551            language: "en",
552        }));
553    }
554
555    #[test]
556    fn literal_typed() {
557        let datatype = xsd::integer.iriref().to_string();
558        let datatype = NamedNode { iri: &datatype };
559        assert_consistent_term_impl(&Trusted(Literal::Typed {
560            value: "42",
561            datatype,
562        }));
563    }
564
565    /*
566    #[test]
567    fn subject_blank_node() {
568        let t: Subject = BlankNode { id: "foo" }.into();
569        assert_consistent_term_impl(&Trusted(t))
570    }
571
572    #[test]
573    fn subject_named_node() {
574        let t: Subject = NamedNode { iri: "tag:foo" }.into();
575        assert_consistent_term_impl(&Trusted(t));
576    }
577
578    #[test]
579    fn subject_triple() {
580        let subject = BlankNode { id: "foo" }.into();
581        let predicate = NamedNode { iri: "tag:bar" };
582        let object = Literal::Simple { value: "baz" }.into();
583        let tr = RioTriple {
584            subject,
585            predicate,
586            object,
587        };
588        let t = Trusted(Subject::Triple(&tr));
589        assert_eq!(t.kind(), TermKind::Triple);
590        assert_eq!(t.iri(), None);
591        assert!(t.triple().is_some());
592    }
593     */
594
595    #[test]
596    fn graph_name_blank_node() {
597        let t: GraphName = BlankNode { id: "foo" }.into();
598        assert_consistent_term_impl(&Trusted(t))
599    }
600
601    #[test]
602    fn graph_name_named_node() {
603        let t: GraphName = NamedNode { iri: "tag:foo" }.into();
604        assert_consistent_term_impl(&Trusted(t));
605    }
606
607    #[test]
608    fn term_blank_node() {
609        let t: RioTerm = BlankNode { id: "foo" }.into();
610        assert_consistent_term_impl(&Trusted(t))
611    }
612
613    #[test]
614    fn term_named_node() {
615        let t: RioTerm = NamedNode { iri: "tag:foo" }.into();
616        assert_consistent_term_impl(&Trusted(t));
617    }
618
619    #[test]
620    fn term_literal_simple() {
621        let t: RioTerm = Literal::Simple { value: "foo" }.into();
622        assert_consistent_term_impl(&Trusted(t));
623    }
624
625    #[test]
626    fn term_literal_language() {
627        let t: RioTerm = Literal::LanguageTaggedString {
628            value: "foo",
629            language: "en",
630        }
631        .into();
632        assert_consistent_term_impl(&Trusted(t));
633    }
634
635    #[test]
636    fn term_literal_typed() {
637        let datatype = xsd::integer.iriref().to_string();
638        let datatype = NamedNode { iri: &datatype };
639        let t: RioTerm = Literal::Typed {
640            value: "42",
641            datatype,
642        }
643        .into();
644        assert_consistent_term_impl(&Trusted(t));
645    }
646
647    #[test]
648    fn term_triple() {
649        let subject = BlankNode { id: "foo" }.into();
650        let predicate = NamedNode { iri: "tag:bar" };
651        let object = Literal::Simple { value: "baz" }.into();
652        let tr = RioTriple {
653            subject,
654            predicate,
655            object,
656        };
657        let t = RioTerm::Triple(&tr);
658        assert_consistent_term_impl(&Trusted(t));
659    }
660
661    #[test]
662    fn gterm_blank_node() {
663        let t: RioTerm = BlankNode { id: "foo" }.into();
664        assert_consistent_term_impl(&Trusted(t))
665    }
666
667    #[test]
668    fn gterm_named_node() {
669        let t: RioTerm = NamedNode { iri: "tag:foo" }.into();
670        assert_consistent_term_impl(&Trusted(t));
671    }
672
673    #[test]
674    fn gterm_literal_simple() {
675        let t: RioTerm = Literal::Simple { value: "foo" }.into();
676        assert_consistent_term_impl(&Trusted(t));
677    }
678
679    #[test]
680    fn gterm_literal_language() {
681        let t: RioTerm = Literal::LanguageTaggedString {
682            value: "foo",
683            language: "en",
684        }
685        .into();
686        assert_consistent_term_impl(&Trusted(t));
687    }
688
689    #[test]
690    fn gterm_literal_typed() {
691        let datatype = xsd::integer.iriref().to_string();
692        let datatype = NamedNode { iri: &datatype };
693        let t: RioTerm = Literal::Typed {
694            value: "42",
695            datatype,
696        }
697        .into();
698        assert_consistent_term_impl(&Trusted(t));
699    }
700
701    #[test]
702    fn gterm_triple() {
703        let subject = BlankNode { id: "foo" }.into();
704        let predicate = NamedNode { iri: "tag:bar" };
705        let object = Literal::Simple { value: "baz" }.into();
706        let tr = RioTriple {
707            subject,
708            predicate,
709            object,
710        };
711        let t = RioTerm::Triple(&tr);
712        assert_consistent_term_impl(&Trusted(t));
713    }
714
715    #[test]
716    fn gterm_variable() {
717        let t: GeneralizedTerm = Variable { name: "foo" }.into();
718        assert_consistent_term_impl(&Trusted(t))
719    }
720}