Skip to main content

rdf_syntax/interpretation/
fallible.rs

1use core::fmt;
2use std::{borrow::Cow, convert::Infallible};
3
4use into_owned_trait::MapIntoOwned;
5use iref::{Iri, IriBuf};
6use rdf_types::Domain;
7
8use super::GroundInterpretation;
9use crate::{
10	BlankId, BlankIdBuf, CowGroundTerm, CowId, CowLiteral, CowTerm, GroundInterpretationMut,
11	GroundTerm, GroundTermRef, IdRef, Literal, LiteralRef, Term, TermRef,
12	interpretation::{
13		Interpretation, InterpretationMut, ReverseGroundInterpretation, ReverseInterpretation,
14	},
15	util::InfallibleIterator,
16};
17
18/// Fallible ground interpretation.
19///
20/// Fallible counterpart of [`GroundInterpretation`], for interpretations
21/// backed by I/O or otherwise fallible storage.
22pub trait TryGroundInterpretation: Domain {
23	/// Error type.
24	type Error: fmt::Debug + fmt::Display;
25
26	/// Interprets the given IRI, if possible.
27	fn try_iri(&self, iri: &Iri) -> Result<Option<Self::Resource>, Self::Error>;
28
29	/// Interprets the given literal, if possible.
30	fn try_literal<'a>(
31		&self,
32		literal: impl Into<LiteralRef<'a>>,
33	) -> Result<Option<Self::Resource>, Self::Error>;
34
35	/// Interprets the given ground term (an IRI or a literal), if possible.
36	fn try_ground_term<'a>(
37		&self,
38		term: impl Into<GroundTermRef<'a>>,
39	) -> Result<Option<Self::Resource>, Self::Error> {
40		match term.into() {
41			GroundTermRef::Iri(iri) => self.try_iri(iri),
42			GroundTermRef::Literal(l) => self.try_literal(l),
43		}
44	}
45}
46
47/// Any non-fallible interpretation can be used as fallible, with the
48/// [`Infallible`] error type.
49impl<I: GroundInterpretation> TryGroundInterpretation for I {
50	type Error = Infallible;
51
52	fn try_iri(&self, iri: &Iri) -> Result<Option<Self::Resource>, Self::Error> {
53		Ok(self.iri(iri))
54	}
55
56	fn try_literal<'a>(
57		&self,
58		literal: impl Into<LiteralRef<'a>>,
59	) -> Result<Option<Self::Resource>, Self::Error> {
60		Ok(self.literal(literal))
61	}
62
63	fn try_ground_term<'a>(
64		&self,
65		term: impl Into<GroundTermRef<'a>>,
66	) -> Result<Option<Self::Resource>, Self::Error> {
67		Ok(self.ground_term(term))
68	}
69}
70
71/// Mutable fallible ground interpretation.
72pub trait TryGroundInterpretationMut: TryGroundInterpretation {
73	/// Interprets the given IRI, inserting a fresh resource for it if none
74	/// exists yet.
75	fn try_insert_iri<'a>(
76		&mut self,
77		iri: impl Into<Cow<'a, Iri>>,
78	) -> Result<Self::Resource, Self::Error>;
79
80	/// Interprets the given literal, inserting a fresh resource for it if
81	/// none exists yet.
82	fn try_insert_literal<'a>(
83		&mut self,
84		literal: impl Into<CowLiteral<'a>>,
85	) -> Result<Self::Resource, Self::Error>;
86
87	/// Interprets the given ground term, inserting a fresh resource for it
88	/// if none exists yet.
89	fn try_insert_ground_term<'a>(
90		&mut self,
91		term: impl Into<CowGroundTerm<'a>>,
92	) -> Result<Self::Resource, Self::Error> {
93		match term.into() {
94			CowGroundTerm::Iri(iri) => self.try_insert_iri(iri),
95			CowGroundTerm::Literal(literal) => self.try_insert_literal(literal),
96		}
97	}
98}
99
100/// Any mutable ground interpretation can be used as fallible, with the
101/// [`Infallible`] error type.
102impl<I: GroundInterpretationMut> TryGroundInterpretationMut for I {
103	fn try_insert_iri<'a>(
104		&mut self,
105		iri: impl Into<Cow<'a, Iri>>,
106	) -> Result<Self::Resource, Self::Error> {
107		Ok(self.insert_iri(iri))
108	}
109
110	fn try_insert_literal<'a>(
111		&mut self,
112		literal: impl Into<CowLiteral<'a>>,
113	) -> Result<Self::Resource, Self::Error> {
114		Ok(self.insert_literal(literal))
115	}
116
117	fn try_insert_ground_term<'a>(
118		&mut self,
119		term: impl Into<CowGroundTerm<'a>>,
120	) -> Result<Self::Resource, Self::Error> {
121		Ok(self.insert_ground_term(term))
122	}
123}
124
125/// Fallible reverse ground interpretation.
126pub trait TryReverseGroundInterpretation: TryGroundInterpretation {
127	/// Iterator over the IRIs of a resource.
128	type TryIris<'a>: Iterator<Item = Result<IriBuf, Self::Error>>
129	where
130		Self: 'a;
131
132	/// Iterator over the literals of a resource.
133	type TryLiterals<'a>: Iterator<Item = Result<Literal, Self::Error>>
134	where
135		Self: 'a;
136
137	/// Returns an iterator over the IRIs of `resource`.
138	fn try_iris_of<'a>(
139		&'a self,
140		resource: &'a Self::Resource,
141	) -> Result<Self::TryIris<'a>, Self::Error>;
142
143	/// Returns an iterator over the literals of `resource`.
144	fn try_literals_of<'a>(
145		&'a self,
146		resource: &'a Self::Resource,
147	) -> Result<Self::TryLiterals<'a>, Self::Error>;
148
149	/// Returns an iterator over the ground terms (IRIs and literals) of
150	/// `resource`.
151	fn try_ground_terms_of<'a>(
152		&'a self,
153		resource: &'a Self::Resource,
154	) -> Result<TryGroundTermsOf<'a, Self>, Self::Error> {
155		Ok(TryGroundTermsOf {
156			iris: self.try_iris_of(resource)?,
157			literals: self.try_literals_of(resource)?,
158		})
159	}
160
161	/// Checks whether `resource` has no ground term lexical representation.
162	fn try_is_anonymous(&self, resource: &Self::Resource) -> Result<bool, Self::Error> {
163		Ok(self
164			.try_ground_terms_of(resource)?
165			.next()
166			.transpose()?
167			.is_none())
168	}
169}
170
171impl<I: ReverseGroundInterpretation> TryReverseGroundInterpretation for I {
172	type TryIris<'a>
173		= InfallibleIterator<MapIntoOwned<I::Iris<'a>>>
174	where
175		Self: 'a;
176
177	type TryLiterals<'a>
178		= InfallibleIterator<MapIntoOwned<I::Literals<'a>>>
179	where
180		Self: 'a;
181
182	fn try_iris_of<'a>(
183		&'a self,
184		resource: &'a Self::Resource,
185	) -> Result<Self::TryIris<'a>, Self::Error> {
186		Ok(InfallibleIterator(MapIntoOwned(self.iris_of(resource))))
187	}
188
189	fn try_literals_of<'a>(
190		&'a self,
191		resource: &'a Self::Resource,
192	) -> Result<Self::TryLiterals<'a>, Self::Error> {
193		Ok(InfallibleIterator(MapIntoOwned(self.literals_of(resource))))
194	}
195
196	fn try_is_anonymous(&self, resource: &Self::Resource) -> Result<bool, Self::Error> {
197		Ok(self.is_anonymous(resource))
198	}
199}
200
201/// Iterator over the ground terms of a resource.
202///
203/// Created by [`TryReverseGroundInterpretation::try_ground_terms_of`].
204pub struct TryGroundTermsOf<'a, I: 'a + ?Sized + TryReverseGroundInterpretation> {
205	iris: I::TryIris<'a>,
206	literals: I::TryLiterals<'a>,
207}
208
209impl<'a, I: 'a + ?Sized + TryReverseGroundInterpretation> Iterator for TryGroundTermsOf<'a, I> {
210	type Item = Result<GroundTerm, I::Error>;
211
212	fn next(&mut self) -> Option<Self::Item> {
213		self.iris
214			.next()
215			.map(|r| r.map(GroundTerm::Iri))
216			.or_else(|| self.literals.next().map(|r| r.map(GroundTerm::Literal)))
217	}
218}
219
220/// Fallible interpretation.
221///
222/// Same as a fallible ground interpretation, but also interprets blank node
223/// identifiers.
224pub trait TryInterpretation: TryGroundInterpretation {
225	/// Interprets the given blank node identifier, if possible.
226	fn try_blank_id(&self, blank_id: &BlankId) -> Result<Option<Self::Resource>, Self::Error>;
227
228	/// Interprets the given term (a blank node identifier or a ground
229	/// term), if possible.
230	fn try_term<'a>(
231		&self,
232		term: impl Into<TermRef<'a>>,
233	) -> Result<Option<Self::Resource>, Self::Error> {
234		match term.into() {
235			TermRef::BlankId(blank_id) => self.try_blank_id(blank_id),
236			TermRef::Ground(term) => self.try_ground_term(term),
237		}
238	}
239
240	/// Interprets the given identifier (a blank node identifier or an IRI),
241	/// if possible.
242	fn try_id<'a>(&self, id: impl Into<IdRef<'a>>) -> Result<Option<Self::Resource>, Self::Error> {
243		match id.into() {
244			IdRef::BlankId(blank_id) => self.try_blank_id(blank_id),
245			IdRef::Iri(iri) => self.try_iri(iri),
246		}
247	}
248}
249
250/// Any non-fallible interpretation is can be used a fallible, with the
251/// [`Infallible`] error type.
252impl<I: Interpretation> TryInterpretation for I {
253	fn try_blank_id(&self, blank_id: &BlankId) -> Result<Option<Self::Resource>, Self::Error> {
254		Ok(self.blank_id(blank_id))
255	}
256
257	fn try_term<'a>(
258		&self,
259		term: impl Into<TermRef<'a>>,
260	) -> Result<Option<Self::Resource>, Self::Error> {
261		Ok(self.term(term))
262	}
263
264	fn try_id<'a>(&self, id: impl Into<IdRef<'a>>) -> Result<Option<Self::Resource>, Self::Error> {
265		Ok(self.id(id))
266	}
267}
268
269/// Mutable fallible interpretation.
270pub trait TryInterpretationMut: TryInterpretation + TryGroundInterpretationMut {
271	/// Interprets the given blank node identifier, inserting a fresh
272	/// resource for it if none exists yet.
273	fn try_insert_blank_id<'a>(
274		&mut self,
275		blank_id: impl Into<Cow<'a, BlankId>>,
276	) -> Result<Self::Resource, Self::Error>;
277
278	/// Interprets the given term, inserting a fresh resource for it if none
279	/// exists yet.
280	fn try_insert_term<'a>(
281		&mut self,
282		term: impl Into<CowTerm<'a>>,
283	) -> Result<Self::Resource, Self::Error> {
284		match term.into() {
285			CowTerm::BlankId(blank_id) => self.try_insert_blank_id(blank_id),
286			CowTerm::Ground(term) => self.try_insert_ground_term(term),
287		}
288	}
289
290	/// Interprets the given identifier, inserting a fresh resource for it
291	/// if none exists yet.
292	fn try_insert_id<'a>(
293		&mut self,
294		term: impl Into<CowId<'a>>,
295	) -> Result<Self::Resource, Self::Error> {
296		match term.into() {
297			CowId::BlankId(blank_id) => self.try_insert_blank_id(blank_id),
298			CowId::Iri(iri) => self.try_insert_iri(iri),
299		}
300	}
301}
302
303/// Any non-fallible mutable interpretation can be used as fallible, with the
304/// [`Infallible`] error type.
305impl<I: InterpretationMut> TryInterpretationMut for I {
306	fn try_insert_blank_id<'a>(
307		&mut self,
308		blank_id: impl Into<Cow<'a, BlankId>>,
309	) -> Result<Self::Resource, Self::Error> {
310		Ok(self.insert_blank_id(blank_id))
311	}
312
313	fn try_insert_term<'a>(
314		&mut self,
315		term: impl Into<CowTerm<'a>>,
316	) -> Result<Self::Resource, Self::Error> {
317		Ok(self.insert_term(term))
318	}
319
320	fn try_insert_id<'a>(
321		&mut self,
322		term: impl Into<CowId<'a>>,
323	) -> Result<Self::Resource, Self::Error> {
324		Ok(self.insert_id(term))
325	}
326}
327
328/// Fallible reverse interpretation.
329pub trait TryReverseInterpretation: TryReverseGroundInterpretation {
330	/// Iterator over the blank node identifiers of a resource.
331	type TryBlankIds<'a>: Iterator<Item = Result<BlankIdBuf, Self::Error>>
332	where
333		Self: 'a;
334
335	/// Returns an iterator over the blank node identifiers of `resource`.
336	fn try_blank_ids_of<'a>(
337		&'a self,
338		resource: &'a Self::Resource,
339	) -> Result<Self::TryBlankIds<'a>, Self::Error>;
340
341	/// Returns an iterator over the terms (ground terms and blank node
342	/// identifiers) of `resource`.
343	fn try_terms_of<'a>(
344		&'a self,
345		resource: &'a Self::Resource,
346	) -> Result<TryTermsOf<'a, Self>, Self::Error> {
347		Ok(TryTermsOf {
348			terms: self.try_ground_terms_of(resource)?,
349			blank_ids: self.try_blank_ids_of(resource)?,
350		})
351	}
352}
353
354/// Any non-fallible reverse interpretation can be used as fallible, with the
355/// [`Infallible`] error type.
356impl<I: ReverseInterpretation> TryReverseInterpretation for I {
357	type TryBlankIds<'a>
358		= InfallibleIterator<MapIntoOwned<I::BlankIds<'a>>>
359	where
360		Self: 'a;
361
362	fn try_blank_ids_of<'a>(
363		&'a self,
364		resource: &'a Self::Resource,
365	) -> Result<Self::TryBlankIds<'a>, Self::Error> {
366		Ok(InfallibleIterator(MapIntoOwned(
367			self.blank_ids_of(resource),
368		)))
369	}
370}
371
372/// Iterator over the terms of a resource.
373///
374/// Created by [`TryReverseInterpretation::try_terms_of`].
375pub struct TryTermsOf<'a, I: 'a + ?Sized + TryReverseInterpretation> {
376	terms: TryGroundTermsOf<'a, I>,
377	blank_ids: I::TryBlankIds<'a>,
378}
379
380impl<'a, I: 'a + ?Sized + TryReverseInterpretation> Iterator for TryTermsOf<'a, I> {
381	type Item = Result<Term, I::Error>;
382
383	fn next(&mut self) -> Option<Self::Item> {
384		self.terms
385			.next()
386			.map(|r| r.map(Term::Ground))
387			.or_else(|| self.blank_ids.next().map(|r| r.map(Term::BlankId)))
388	}
389}