Skip to main content

rdf_syntax/interpretation/
mod.rs

1//! Resource interpretations.
2use std::borrow::Cow;
3
4use iref::Iri;
5use rdf_types::Domain;
6
7use crate::{
8	BlankId, CowGroundTerm, CowId, CowLiteral, CowTerm, GroundTermRef, IdRef, LiteralRef, TermRef,
9};
10
11pub mod fallible;
12mod r#impl;
13
14pub use fallible::*;
15pub use r#impl::*;
16
17/// RDF ground resource interpretation.
18///
19/// A ground interpretation maps *ground* lexical terms ([`crate::GroundTerm`],
20/// i.e. IRIs and literals) to the resources of a [`Domain`]. See
21/// [`Interpretation`] for a refinement that also interprets blank node
22/// identifiers.
23pub trait GroundInterpretation: Domain {
24	/// Interprets the given IRI, if possible.
25	fn iri(&self, iri: &Iri) -> Option<Self::Resource>;
26
27	/// Interprets the given literal, if possible.
28	fn literal<'a>(&self, literal: impl Into<LiteralRef<'a>>) -> Option<Self::Resource>;
29
30	/// Interprets the given ground term (an IRI or a literal), if possible.
31	fn ground_term<'a>(&self, term: impl Into<GroundTermRef<'a>>) -> Option<Self::Resource> {
32		match term.into() {
33			GroundTermRef::Iri(iri) => self.iri(iri),
34			GroundTermRef::Literal(l) => self.literal(l),
35		}
36	}
37}
38
39/// Mutable ground interpretation, able to create new interpreted resources
40/// on demand.
41pub trait GroundInterpretationMut: GroundInterpretation {
42	/// Interprets the given IRI, inserting a fresh resource for it if none
43	/// exists yet.
44	fn insert_iri<'a>(&mut self, iri: impl Into<Cow<'a, Iri>>) -> Self::Resource;
45
46	/// Interprets the given literal, inserting a fresh resource for it if
47	/// none exists yet.
48	fn insert_literal<'a>(&mut self, literal: impl Into<CowLiteral<'a>>) -> Self::Resource;
49
50	/// Interprets the given ground term, inserting a fresh resource for it
51	/// if none exists yet.
52	fn insert_ground_term<'a>(&mut self, term: impl Into<CowGroundTerm<'a>>) -> Self::Resource {
53		match term.into() {
54			CowGroundTerm::Iri(iri) => self.insert_iri(iri),
55			CowGroundTerm::Literal(literal) => self.insert_literal(literal),
56		}
57	}
58}
59
60/// Reverse ground interpretation, listing the ground lexical terms of a
61/// given resource.
62pub trait ReverseGroundInterpretation: GroundInterpretation {
63	/// Iterator over the IRIs of a resource.
64	type Iris<'a>: Iterator<Item = &'a Iri>
65	where
66		Self: 'a;
67
68	/// Iterator over the literals of a resource.
69	type Literals<'a>: Iterator<Item = LiteralRef<'a>>
70	where
71		Self: 'a;
72
73	/// Returns an iterator over the IRIs of `resource`.
74	fn iris_of<'a>(&'a self, resource: &'a Self::Resource) -> Self::Iris<'a>;
75
76	/// Returns an iterator over the literals of `resource`.
77	fn literals_of<'a>(&'a self, resource: &'a Self::Resource) -> Self::Literals<'a>;
78
79	/// Returns an iterator over the ground terms (IRIs and literals) of
80	/// `resource`.
81	fn ground_terms_of<'a>(&'a self, resource: &'a Self::Resource) -> GroundTermsOf<'a, Self> {
82		GroundTermsOf {
83			iris: self.iris_of(resource),
84			literals: self.literals_of(resource),
85		}
86	}
87
88	/// Checks whether `resource` has no ground term lexical representation.
89	fn is_anonymous(&self, resource: &Self::Resource) -> bool {
90		self.ground_terms_of(resource).next().is_none()
91	}
92}
93
94/// Iterator over the ground terms of a resource.
95///
96/// Created by [`ReverseGroundInterpretation::ground_terms_of`].
97pub struct GroundTermsOf<'a, I: 'a + ?Sized + ReverseGroundInterpretation> {
98	iris: I::Iris<'a>,
99	literals: I::Literals<'a>,
100}
101
102impl<'a, I: 'a + ?Sized + ReverseGroundInterpretation> Iterator for GroundTermsOf<'a, I> {
103	type Item = GroundTermRef<'a>;
104
105	fn next(&mut self) -> Option<Self::Item> {
106		self.iris
107			.next()
108			.map(GroundTermRef::Iri)
109			.or_else(|| self.literals.next().map(GroundTermRef::Literal))
110	}
111}
112
113/// RDF resource interpretation.
114///
115/// In addition to ground terms, a full interpretation also maps blank node
116/// identifiers to resources.
117pub trait Interpretation: GroundInterpretation {
118	/// Interprets the given blank node identifier, if possible.
119	fn blank_id(&self, blank_id: &BlankId) -> Option<Self::Resource>;
120
121	/// Interprets the given term (a blank node identifier or a ground term),
122	/// if possible.
123	fn term<'a>(&self, term: impl Into<TermRef<'a>>) -> Option<Self::Resource> {
124		match term.into() {
125			TermRef::BlankId(blank_id) => self.blank_id(blank_id),
126			TermRef::Ground(term) => self.ground_term(term),
127		}
128	}
129
130	/// Interprets the given identifier (a blank node identifier or an IRI),
131	/// if possible.
132	fn id<'a>(&self, id: impl Into<IdRef<'a>>) -> Option<Self::Resource> {
133		match id.into() {
134			IdRef::BlankId(blank_id) => self.blank_id(blank_id),
135			IdRef::Iri(iri) => self.iri(iri),
136		}
137	}
138}
139
140/// Mutable resource interpretation, able to create new interpreted
141/// resources on demand.
142pub trait InterpretationMut: Interpretation + GroundInterpretationMut {
143	/// Interprets the given blank node identifier, inserting a fresh
144	/// resource for it if none exists yet.
145	fn insert_blank_id<'a>(&mut self, blank_id: impl Into<Cow<'a, BlankId>>) -> Self::Resource;
146
147	/// Interprets the given term, inserting a fresh resource for it if none
148	/// exists yet.
149	fn insert_term<'a>(&mut self, term: impl Into<CowTerm<'a>>) -> Self::Resource {
150		match term.into() {
151			CowTerm::BlankId(blank_id) => self.insert_blank_id(blank_id),
152			CowTerm::Ground(term) => self.insert_ground_term(term),
153		}
154	}
155
156	/// Interprets the given identifier, inserting a fresh resource for it
157	/// if none exists yet.
158	fn insert_id<'a>(&mut self, term: impl Into<CowId<'a>>) -> Self::Resource {
159		match term.into() {
160			CowId::BlankId(blank_id) => self.insert_blank_id(blank_id),
161			CowId::Iri(iri) => self.insert_iri(iri),
162		}
163	}
164}
165
166/// Reverse resource interpretation, listing the lexical terms of a given
167/// resource.
168pub trait ReverseInterpretation: ReverseGroundInterpretation {
169	/// Iterator over the blank node identifiers of a resource.
170	type BlankIds<'a>: Iterator<Item = &'a BlankId>
171	where
172		Self: 'a;
173
174	/// Returns an iterator over the blank node identifiers of `resource`.
175	fn blank_ids_of<'a>(&'a self, resource: &'a Self::Resource) -> Self::BlankIds<'a>;
176
177	/// Returns an iterator over the terms (ground terms and blank node
178	/// identifiers) of `resource`.
179	fn terms_of<'a>(&'a self, resource: &'a Self::Resource) -> TermsOf<'a, Self> {
180		TermsOf {
181			terms: self.ground_terms_of(resource),
182			blank_ids: self.blank_ids_of(resource),
183		}
184	}
185}
186
187/// Iterator over the terms of a resource.
188///
189/// Created by [`ReverseInterpretation::terms_of`].
190pub struct TermsOf<'a, I: 'a + ?Sized + ReverseInterpretation> {
191	terms: GroundTermsOf<'a, I>,
192	blank_ids: I::BlankIds<'a>,
193}
194
195impl<'a, I: 'a + ?Sized + ReverseInterpretation> Iterator for TermsOf<'a, I> {
196	type Item = TermRef<'a>;
197
198	fn next(&mut self) -> Option<Self::Item> {
199		self.terms
200			.next()
201			.map(TermRef::Ground)
202			.or_else(|| self.blank_ids.next().map(TermRef::BlankId))
203	}
204}