Skip to main content

linked_data_next/
predicate.rs

1use iref::{Iri, IriBuf};
2use rdf_types::{
3	BlankId, BlankIdBuf, Id, Interpretation, RDF_FIRST, RDF_REST, Vocabulary,
4	dataset::PatternMatchingDataset,
5	interpretation::{
6		IriInterpretation, ReverseBlankIdInterpretation, ReverseIdInterpretation,
7		ReverseIriInterpretation,
8	},
9	vocabulary::{BlankIdVocabularyMut, IriVocabularyMut},
10};
11use std::collections::HashSet;
12use std::hash::Hash;
13
14use crate::{
15	Context, FromLinkedDataError, LinkedDataDeserializeSubject, LinkedDataResource,
16	LinkedDataSubject, rdf_list::RdfList,
17};
18
19/// Type representing the objects of an RDF subject's predicate binding.
20pub trait LinkedDataPredicateObjects<I: Interpretation = (), V: Vocabulary = ()> {
21	fn visit_objects<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
22	where
23		S: PredicateObjectsVisitor<I, V>;
24}
25
26impl<I: Interpretation, V: Vocabulary> LinkedDataPredicateObjects<I, V> for () {
27	fn visit_objects<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
28	where
29		S: PredicateObjectsVisitor<I, V>,
30	{
31		visitor.end()
32	}
33}
34
35impl<I: Interpretation, V: Vocabulary, T: ?Sized + LinkedDataPredicateObjects<I, V>>
36	LinkedDataPredicateObjects<I, V> for &T
37{
38	fn visit_objects<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
39	where
40		S: PredicateObjectsVisitor<I, V>,
41	{
42		T::visit_objects(self, visitor)
43	}
44}
45
46impl<I: Interpretation, V: Vocabulary, T: ?Sized + LinkedDataPredicateObjects<I, V>>
47	LinkedDataPredicateObjects<I, V> for Box<T>
48{
49	fn visit_objects<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
50	where
51		S: PredicateObjectsVisitor<I, V>,
52	{
53		T::visit_objects(self, visitor)
54	}
55}
56
57impl<I: Interpretation, V: Vocabulary, T: LinkedDataSubject<I, V> + LinkedDataResource<I, V>>
58	LinkedDataPredicateObjects<I, V> for Option<T>
59{
60	fn visit_objects<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
61	where
62		S: PredicateObjectsVisitor<I, V>,
63	{
64		if let Some(t) = self {
65			visitor.object(t)?;
66		}
67
68		visitor.end()
69	}
70}
71
72impl<I: Interpretation, V: Vocabulary, T: LinkedDataSubject<I, V> + LinkedDataResource<I, V>>
73	LinkedDataPredicateObjects<I, V> for [T]
74{
75	fn visit_objects<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
76	where
77		S: PredicateObjectsVisitor<I, V>,
78	{
79		for t in self {
80			visitor.object(t)?;
81		}
82
83		visitor.end()
84	}
85}
86
87/// Serialized as an `rdf:List` (a chain of blank nodes linked by
88/// `rdf:first`/`rdf:rest`, terminated by `rdf:nil`) so that element order is
89/// preserved.
90impl<
91	I: Interpretation,
92	V: Vocabulary + IriVocabularyMut,
93	T: LinkedDataSubject<I, V> + LinkedDataResource<I, V>,
94> LinkedDataPredicateObjects<I, V> for Vec<T>
95{
96	fn visit_objects<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
97	where
98		S: PredicateObjectsVisitor<I, V>,
99	{
100		visitor.object(&RdfList(self.as_slice()))?;
101		visitor.end()
102	}
103}
104
105impl<I: Interpretation, V: Vocabulary, T: LinkedDataSubject<I, V> + LinkedDataResource<I, V>>
106	LinkedDataPredicateObjects<I, V> for HashSet<T>
107{
108	fn visit_objects<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
109	where
110		S: PredicateObjectsVisitor<I, V>,
111	{
112		for t in self.iter() {
113			visitor.object(t)?;
114		}
115
116		visitor.end()
117	}
118}
119
120impl<I: Interpretation, V: Vocabulary> LinkedDataPredicateObjects<I, V> for Iri
121where
122	V: IriVocabularyMut,
123{
124	fn visit_objects<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
125	where
126		S: PredicateObjectsVisitor<I, V>,
127	{
128		visitor.object(self)?;
129		visitor.end()
130	}
131}
132
133impl<I: Interpretation, V: Vocabulary> LinkedDataPredicateObjects<I, V> for IriBuf
134where
135	V: IriVocabularyMut,
136{
137	fn visit_objects<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
138	where
139		S: PredicateObjectsVisitor<I, V>,
140	{
141		visitor.object(self)?;
142		visitor.end()
143	}
144}
145
146impl<I: Interpretation, V: Vocabulary> LinkedDataPredicateObjects<I, V> for BlankId
147where
148	V: BlankIdVocabularyMut,
149{
150	fn visit_objects<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
151	where
152		S: PredicateObjectsVisitor<I, V>,
153	{
154		visitor.object(self)?;
155		visitor.end()
156	}
157}
158
159impl<I: Interpretation, V: Vocabulary> LinkedDataPredicateObjects<I, V> for BlankIdBuf
160where
161	V: BlankIdVocabularyMut,
162{
163	fn visit_objects<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
164	where
165		S: PredicateObjectsVisitor<I, V>,
166	{
167		visitor.object(self)?;
168		visitor.end()
169	}
170}
171
172impl<I: Interpretation, V: Vocabulary, T, B> LinkedDataPredicateObjects<I, V> for Id<T, B>
173where
174	T: LinkedDataPredicateObjects<I, V>,
175	B: LinkedDataPredicateObjects<I, V>,
176{
177	fn visit_objects<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
178	where
179		S: PredicateObjectsVisitor<I, V>,
180	{
181		match self {
182			Self::Iri(i) => i.visit_objects(visitor),
183			Self::Blank(b) => b.visit_objects(visitor),
184		}
185	}
186}
187
188pub trait PredicateObjectsVisitor<I: Interpretation, V: Vocabulary> {
189	type Ok;
190	type Error;
191
192	fn object<T>(&mut self, value: &T) -> Result<(), Self::Error>
193	where
194		T: ?Sized + LinkedDataResource<I, V> + LinkedDataSubject<I, V>;
195
196	fn end(self) -> Result<Self::Ok, Self::Error>;
197}
198
199pub trait LinkedDataDeserializePredicateObjects<I: Interpretation = (), V: Vocabulary = ()>:
200	Sized
201{
202	fn deserialize_objects_in<'a, D>(
203		vocabulary: &V,
204		interpretation: &I,
205		dataset: &D,
206		graph: Option<&I::Resource>,
207		objects: impl IntoIterator<Item = &'a I::Resource>,
208		context: Context<I>,
209	) -> Result<Self, FromLinkedDataError>
210	where
211		I::Resource: 'a,
212		D: PatternMatchingDataset<Resource = I::Resource>;
213
214	fn deserialize_objects<'a, D>(
215		vocabulary: &V,
216		interpretation: &I,
217		dataset: &D,
218		graph: Option<&I::Resource>,
219		objects: impl IntoIterator<Item = &'a I::Resource>,
220	) -> Result<Self, FromLinkedDataError>
221	where
222		I::Resource: 'a,
223		D: PatternMatchingDataset<Resource = I::Resource>,
224	{
225		Self::deserialize_objects_in(
226			vocabulary,
227			interpretation,
228			dataset,
229			graph,
230			objects,
231			Context::default(),
232		)
233	}
234}
235
236macro_rules! deserialize_single_object {
237	() => {
238		fn deserialize_objects_in<'a, D>(
239			vocabulary: &V,
240			interpretation: &I,
241			dataset: &D,
242			graph: Option<&I::Resource>,
243			objects: impl IntoIterator<Item = &'a I::Resource>,
244			context: $crate::Context<I>,
245		) -> Result<Self, FromLinkedDataError>
246		where
247			I::Resource: 'a,
248			D: PatternMatchingDataset<Resource = I::Resource>,
249		{
250			use crate::LinkedDataDeserializeSubject;
251			let mut objects = objects.into_iter();
252			match objects.next() {
253				Some(object) => {
254					if objects.next().is_none() {
255						Self::deserialize_subject_in(
256							vocabulary,
257							interpretation,
258							dataset,
259							graph,
260							object,
261							context,
262						)
263					} else {
264						Err(FromLinkedDataError::TooManyValues(
265							context.into_iris(vocabulary, interpretation),
266						))
267					}
268				}
269				None => Err(FromLinkedDataError::MissingRequiredValue(
270					context.into_iris(vocabulary, interpretation),
271				)),
272			}
273		}
274	};
275}
276
277impl<I: Interpretation, V: Vocabulary> LinkedDataDeserializePredicateObjects<I, V> for IriBuf
278where
279	I: ReverseIriInterpretation<Iri = V::Iri>,
280{
281	deserialize_single_object!();
282}
283
284impl<I: Interpretation, V: Vocabulary> LinkedDataDeserializePredicateObjects<I, V> for BlankIdBuf
285where
286	I: ReverseIriInterpretation<Iri = V::Iri> + ReverseBlankIdInterpretation<BlankId = V::BlankId>,
287{
288	deserialize_single_object!();
289}
290
291impl<I: Interpretation, V: Vocabulary> LinkedDataDeserializePredicateObjects<I, V> for Id
292where
293	I: ReverseIdInterpretation<Iri = V::Iri, BlankId = V::BlankId>,
294{
295	deserialize_single_object!();
296}
297
298impl<I: Interpretation, V: Vocabulary, T: LinkedDataDeserializePredicateObjects<I, V>>
299	LinkedDataDeserializePredicateObjects<I, V> for Box<T>
300{
301	fn deserialize_objects_in<'a, D>(
302		vocabulary: &V,
303		interpretation: &I,
304		dataset: &D,
305		graph: Option<&I::Resource>,
306		objects: impl IntoIterator<Item = &'a I::Resource>,
307		context: Context<I>,
308	) -> Result<Self, FromLinkedDataError>
309	where
310		I::Resource: 'a,
311		D: PatternMatchingDataset<Resource = I::Resource>,
312	{
313		T::deserialize_objects_in(vocabulary, interpretation, dataset, graph, objects, context)
314			.map(Box::new)
315	}
316}
317
318impl<I: Interpretation, V: Vocabulary, T: LinkedDataDeserializeSubject<I, V>>
319	LinkedDataDeserializePredicateObjects<I, V> for Option<T>
320where
321	I: ReverseIriInterpretation<Iri = V::Iri>,
322{
323	fn deserialize_objects_in<'a, D>(
324		vocabulary: &V,
325		interpretation: &I,
326		dataset: &D,
327		graph: Option<&I::Resource>,
328		objects: impl IntoIterator<Item = &'a I::Resource>,
329		context: Context<I>,
330	) -> Result<Self, FromLinkedDataError>
331	where
332		I::Resource: 'a,
333		D: PatternMatchingDataset<Resource = I::Resource>,
334	{
335		let mut objects = objects.into_iter();
336		match objects.next() {
337			Some(object) => {
338				if objects.next().is_none() {
339					T::deserialize_subject_in(
340						vocabulary,
341						interpretation,
342						dataset,
343						graph,
344						object,
345						context,
346					)
347					.map(Some)
348				} else {
349					Err(FromLinkedDataError::TooManyValues(
350						context.into_iris(vocabulary, interpretation),
351					))
352				}
353			}
354			None => Ok(None),
355		}
356	}
357}
358
359/// Deserialized by walking an `rdf:List` (a chain of blank nodes linked by
360/// `rdf:first`/`rdf:rest`, terminated by `rdf:nil`), preserving element
361/// order. A predicate with no value at all is treated as an empty list.
362impl<I: Interpretation, V: Vocabulary, T: LinkedDataDeserializeSubject<I, V>>
363	LinkedDataDeserializePredicateObjects<I, V> for Vec<T>
364where
365	I: ReverseIriInterpretation<Iri = V::Iri> + IriInterpretation<V::Iri>,
366{
367	fn deserialize_objects_in<'a, D>(
368		vocabulary: &V,
369		interpretation: &I,
370		dataset: &D,
371		graph: Option<&I::Resource>,
372		objects: impl IntoIterator<Item = &'a I::Resource>,
373		context: Context<I>,
374	) -> Result<Self, FromLinkedDataError>
375	where
376		I::Resource: 'a,
377		D: PatternMatchingDataset<Resource = I::Resource>,
378	{
379		let mut objects = objects.into_iter();
380
381		let head = match objects.next() {
382			Some(head) => {
383				if objects.next().is_some() {
384					return Err(FromLinkedDataError::TooManyValues(
385						context.into_iris(vocabulary, interpretation),
386					));
387				}
388
389				head
390			}
391			None => return Ok(Vec::new()),
392		};
393
394		let (Some(first_predicate), Some(rest_predicate)) = (
395			interpretation.lexical_iri_interpretation(vocabulary, RDF_FIRST),
396			interpretation.lexical_iri_interpretation(vocabulary, RDF_REST),
397		) else {
398			return Ok(Vec::new());
399		};
400
401		let mut result = Vec::new();
402		let mut node = head;
403
404		loop {
405			let mut firsts = dataset.quad_objects(graph, node, &first_predicate);
406			let Some(item) = firsts.next() else {
407				break;
408			};
409
410			if firsts.next().is_some() {
411				return Err(FromLinkedDataError::TooManyValues(
412					context.into_iris(vocabulary, interpretation),
413				));
414			}
415
416			result.push(T::deserialize_subject_in(
417				vocabulary,
418				interpretation,
419				dataset,
420				graph,
421				item,
422				context,
423			)?);
424
425			let mut rests = dataset.quad_objects(graph, node, &rest_predicate);
426			match rests.next() {
427				Some(next) => node = next,
428				None => break,
429			}
430		}
431
432		Ok(result)
433	}
434}
435
436impl<I: Interpretation, V: Vocabulary, T: LinkedDataDeserializeSubject<I, V>>
437	LinkedDataDeserializePredicateObjects<I, V> for HashSet<T>
438where
439	I: ReverseIriInterpretation<Iri = V::Iri>,
440	T: Clone + Hash + Eq,
441{
442	fn deserialize_objects_in<'a, D>(
443		vocabulary: &V,
444		interpretation: &I,
445		dataset: &D,
446		graph: Option<&I::Resource>,
447		objects: impl IntoIterator<Item = &'a I::Resource>,
448		context: Context<I>,
449	) -> Result<Self, FromLinkedDataError>
450	where
451		I::Resource: 'a,
452		D: PatternMatchingDataset<Resource = I::Resource>,
453	{
454		objects
455			.into_iter()
456			.map(|object| {
457				T::deserialize_subject_in(
458					vocabulary,
459					interpretation,
460					dataset,
461					graph,
462					object,
463					context,
464				)
465			})
466			.collect::<Result<HashSet<_>, _>>()
467	}
468}