Skip to main content

ld_core/
predicate.rs

1use iri_rs::IriBuf;
2use rdfx::{
3	BlankId, BlankIdBuf, Id, Interpretation,
4	dataset::PatternMatchingDataset,
5	interpretation::{ReverseInterpretation, ReverseLocalInterpretation},
6};
7
8use crate::{
9	Context, FromLinkedDataError, LinkedDataDeserializeSubject, LinkedDataResource,
10	LinkedDataSubject,
11};
12
13/// Type representing the objects of an RDF subject's predicate binding.
14pub trait LinkedDataPredicateObjects<I: Interpretation = ()> {
15	/// Visits the objects this predicate points at.
16	fn visit_objects<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
17	where
18		S: PredicateObjectsVisitor<I>;
19}
20
21impl<I: Interpretation> LinkedDataPredicateObjects<I> for () {
22	fn visit_objects<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
23	where
24		S: PredicateObjectsVisitor<I>,
25	{
26		visitor.end()
27	}
28}
29
30impl<I: Interpretation, T: ?Sized + LinkedDataPredicateObjects<I>> LinkedDataPredicateObjects<I>
31	for &T
32{
33	fn visit_objects<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
34	where
35		S: PredicateObjectsVisitor<I>,
36	{
37		T::visit_objects(self, visitor)
38	}
39}
40
41impl<I: Interpretation, T: ?Sized + LinkedDataPredicateObjects<I>> LinkedDataPredicateObjects<I>
42	for Box<T>
43{
44	fn visit_objects<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
45	where
46		S: PredicateObjectsVisitor<I>,
47	{
48		T::visit_objects(self, visitor)
49	}
50}
51
52impl<I: Interpretation, T: LinkedDataSubject<I> + LinkedDataResource<I>>
53	LinkedDataPredicateObjects<I> for Option<T>
54{
55	fn visit_objects<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
56	where
57		S: PredicateObjectsVisitor<I>,
58	{
59		if let Some(t) = self {
60			visitor.object(t)?;
61		}
62		visitor.end()
63	}
64}
65
66impl<I: Interpretation, T: LinkedDataSubject<I> + LinkedDataResource<I>>
67	LinkedDataPredicateObjects<I> for [T]
68{
69	fn visit_objects<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
70	where
71		S: PredicateObjectsVisitor<I>,
72	{
73		for t in self {
74			visitor.object(t)?;
75		}
76		visitor.end()
77	}
78}
79
80impl<I: Interpretation, T: LinkedDataSubject<I> + LinkedDataResource<I>>
81	LinkedDataPredicateObjects<I> for Vec<T>
82{
83	fn visit_objects<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
84	where
85		S: PredicateObjectsVisitor<I>,
86	{
87		for t in self {
88			visitor.object(t)?;
89		}
90		visitor.end()
91	}
92}
93
94impl<I: Interpretation> LinkedDataPredicateObjects<I> for IriBuf {
95	fn visit_objects<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
96	where
97		S: PredicateObjectsVisitor<I>,
98	{
99		visitor.object(self)?;
100		visitor.end()
101	}
102}
103
104impl<I: Interpretation> LinkedDataPredicateObjects<I> for iri_rs::Iri<&str> {
105	fn visit_objects<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
106	where
107		S: PredicateObjectsVisitor<I>,
108	{
109		visitor.object(self)?;
110		visitor.end()
111	}
112}
113
114impl<I: Interpretation> LinkedDataPredicateObjects<I> for BlankId {
115	fn visit_objects<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
116	where
117		S: PredicateObjectsVisitor<I>,
118	{
119		visitor.object(self)?;
120		visitor.end()
121	}
122}
123
124impl<I: Interpretation> LinkedDataPredicateObjects<I> for BlankIdBuf {
125	fn visit_objects<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
126	where
127		S: PredicateObjectsVisitor<I>,
128	{
129		visitor.object(self)?;
130		visitor.end()
131	}
132}
133
134impl<I: Interpretation> LinkedDataPredicateObjects<I> for Id {
135	fn visit_objects<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
136	where
137		S: PredicateObjectsVisitor<I>,
138	{
139		visitor.object(self)?;
140		visitor.end()
141	}
142}
143
144/// Visitor over the objects of a predicate.
145pub trait PredicateObjectsVisitor<I: Interpretation> {
146	/// Value returned once every object has been visited.
147	type Ok;
148	/// Error type.
149	type Error;
150
151	/// Visits an object of the predicate.
152	fn object<T>(&mut self, value: &T) -> Result<(), Self::Error>
153	where
154		T: ?Sized + LinkedDataResource<I> + LinkedDataSubject<I>;
155
156	/// Ends the objects visit.
157	fn end(self) -> Result<Self::Ok, Self::Error>;
158}
159
160/// Type that can be deserialized from the objects of a predicate.
161pub trait LinkedDataDeserializePredicateObjects<I: Interpretation>: Sized
162where
163	I::Resource: rdfx::Resource,
164{
165	/// Deserializes a value from `objects`, reporting errors against
166	/// `context`.
167	fn deserialize_objects_in<'a, D>(
168		interpretation: &I,
169		dataset: &D,
170		graph: Option<&I::Resource>,
171		objects: impl IntoIterator<Item = &'a I::Resource>,
172		context: Context<I>,
173	) -> Result<Self, FromLinkedDataError>
174	where
175		I::Resource: 'a,
176		D: PatternMatchingDataset<Subject = I::Resource>;
177
178	/// Deserializes a value from `objects`.
179	fn deserialize_objects<'a, D>(
180		interpretation: &I,
181		dataset: &D,
182		graph: Option<&I::Resource>,
183		objects: impl IntoIterator<Item = &'a I::Resource>,
184	) -> Result<Self, FromLinkedDataError>
185	where
186		I::Resource: 'a,
187		D: PatternMatchingDataset<Subject = I::Resource>,
188	{
189		Self::deserialize_objects_in(interpretation, dataset, graph, objects, Context::default())
190	}
191}
192
193macro_rules! deserialize_single_object {
194	() => {
195		fn deserialize_objects_in<'a, D>(
196			interpretation: &I,
197			dataset: &D,
198			graph: Option<&I::Resource>,
199			objects: impl IntoIterator<Item = &'a I::Resource>,
200			context: $crate::Context<I>,
201		) -> Result<Self, FromLinkedDataError>
202		where
203			I::Resource: 'a,
204			D: PatternMatchingDataset<Subject = I::Resource>,
205		{
206			use crate::LinkedDataDeserializeSubject;
207			let mut objects = objects.into_iter();
208			match objects.next() {
209				Some(object) => {
210					if objects.next().is_none() {
211						Self::deserialize_subject_in(
212							interpretation,
213							dataset,
214							graph,
215							object,
216							context,
217						)
218					} else {
219						Err(FromLinkedDataError::TooManyValues(
220							context.into_iris(interpretation),
221						))
222					}
223				}
224				None => Err(FromLinkedDataError::MissingRequiredValue(
225					context.into_iris(interpretation),
226				)),
227			}
228		}
229	};
230}
231
232impl<I: Interpretation> LinkedDataDeserializePredicateObjects<I> for IriBuf
233where
234	I: ReverseInterpretation,
235	I::Resource: rdfx::Resource,
236{
237	deserialize_single_object!();
238}
239
240impl<I: Interpretation> LinkedDataDeserializePredicateObjects<I> for BlankIdBuf
241where
242	I: ReverseInterpretation + ReverseLocalInterpretation,
243	I::Resource: rdfx::Resource,
244{
245	deserialize_single_object!();
246}
247
248impl<I: Interpretation> LinkedDataDeserializePredicateObjects<I> for Id
249where
250	I: ReverseInterpretation + ReverseLocalInterpretation,
251	I::Resource: rdfx::Resource,
252{
253	deserialize_single_object!();
254}
255
256impl<I: Interpretation, T: LinkedDataDeserializePredicateObjects<I>>
257	LinkedDataDeserializePredicateObjects<I> for Box<T>
258where
259	I::Resource: rdfx::Resource,
260{
261	fn deserialize_objects_in<'a, D>(
262		interpretation: &I,
263		dataset: &D,
264		graph: Option<&I::Resource>,
265		objects: impl IntoIterator<Item = &'a I::Resource>,
266		context: Context<I>,
267	) -> Result<Self, FromLinkedDataError>
268	where
269		I::Resource: 'a,
270		D: PatternMatchingDataset<Subject = I::Resource>,
271	{
272		T::deserialize_objects_in(interpretation, dataset, graph, objects, context).map(Box::new)
273	}
274}
275
276impl<I: Interpretation, T: LinkedDataDeserializeSubject<I>> LinkedDataDeserializePredicateObjects<I>
277	for Option<T>
278where
279	I: ReverseInterpretation,
280	I::Resource: rdfx::Resource,
281{
282	fn deserialize_objects_in<'a, D>(
283		interpretation: &I,
284		dataset: &D,
285		graph: Option<&I::Resource>,
286		objects: impl IntoIterator<Item = &'a I::Resource>,
287		context: Context<I>,
288	) -> Result<Self, FromLinkedDataError>
289	where
290		I::Resource: 'a,
291		D: PatternMatchingDataset<Subject = I::Resource>,
292	{
293		let mut objects = objects.into_iter();
294		match objects.next() {
295			Some(object) => {
296				if objects.next().is_none() {
297					T::deserialize_subject_in(interpretation, dataset, graph, object, context)
298						.map(Some)
299				} else {
300					Err(FromLinkedDataError::TooManyValues(
301						context.into_iris(interpretation),
302					))
303				}
304			}
305			None => Ok(None),
306		}
307	}
308}