Skip to main content

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