json_ld_core/rdf/
quad.rs

1use super::{RdfDirection, ValidId, Value};
2use crate::{flattening::NodeMap, ExpandedDocument, FlattenedDocument, LdQuads};
3use rdf_types::vocabulary::IriVocabularyMut;
4use rdf_types::{
5	vocabulary::{BlankIdVocabulary, IriVocabulary, LiteralVocabulary, LiteralVocabularyMut},
6	Generator, Triple, Vocabulary,
7};
8use std::borrow::Cow;
9use std::convert::TryInto;
10use std::hash::Hash;
11
12pub type Quad<T, B, L> =
13	rdf_types::Quad<ValidId<T, B>, ValidId<T, B>, Value<T, B, L>, ValidId<T, B>>;
14
15pub type QuadRef<'a, T, B, L> = rdf_types::Quad<
16	Cow<'a, ValidId<T, B>>,
17	Cow<'a, ValidId<T, B>>,
18	Value<T, B, L>,
19	&'a ValidId<T, B>,
20>;
21
22struct Compound<'a, T, B, L> {
23	graph: Option<&'a ValidId<T, B>>,
24	triples: super::CompoundValueTriples<'a, T, B, L>,
25}
26
27type VocabularyCompoundLiteral<'a, N> = Compound<
28	'a,
29	<N as IriVocabulary>::Iri,
30	<N as BlankIdVocabulary>::BlankId,
31	<N as LiteralVocabulary>::Literal,
32>;
33
34/// Iterator over the RDF Quads of a JSON-LD document.
35pub struct Quads<'a, N: Vocabulary, G: Generator<N>> {
36	vocabulary: &'a mut N,
37	generator: &'a mut G,
38	rdf_direction: Option<RdfDirection>,
39	compound_value: Option<VocabularyCompoundLiteral<'a, N>>,
40	quads: crate::quad::Quads<'a, N::Iri, N::BlankId>,
41	produce_generalized_rdf: bool,
42}
43
44impl<'a, N: Vocabulary, G: Generator<N>> Quads<'a, N, G> {
45	pub fn cloned(self) -> ClonedQuads<'a, N, G> {
46		ClonedQuads { inner: self }
47	}
48}
49
50impl<'a, N: Vocabulary + IriVocabularyMut, G: Generator<N>> Iterator for Quads<'a, N, G>
51where
52	N::Iri: Clone,
53	N::BlankId: Clone,
54	N::Literal: Clone,
55	N: LiteralVocabularyMut,
56{
57	type Item = QuadRef<'a, N::Iri, N::BlankId, N::Literal>;
58
59	fn next(&mut self) -> Option<Self::Item> {
60		loop {
61			if let Some(compound_value) = &mut self.compound_value {
62				match compound_value.triples.next(
63					self.vocabulary,
64					self.generator,
65					self.rdf_direction,
66				) {
67					Some(Triple(subject, property, object)) => {
68						if self.produce_generalized_rdf || !property.is_blank() {
69							break Some(rdf_types::Quad(
70								Cow::Owned(subject),
71								Cow::Owned(property),
72								object,
73								compound_value.graph,
74							));
75						}
76					}
77					None => self.compound_value = None,
78				}
79			}
80
81			match self.quads.next() {
82				Some(crate::quad::QuadRef(graph, subject, property, object)) => {
83					let rdf_graph: Option<&'a ValidId<N::Iri, N::BlankId>> =
84						match graph.map(|r| r.try_into()) {
85							Some(Ok(r)) => Some(r),
86							None => None,
87							_ => continue,
88						};
89
90					let rdf_subject: &'a ValidId<N::Iri, N::BlankId> = match subject.try_into() {
91						Ok(r) => r,
92						Err(_) => continue,
93					};
94
95					let rdf_property: Cow<ValidId<N::Iri, N::BlankId>> = match property {
96						crate::quad::PropertyRef::Type => {
97							Cow::Owned(ValidId::Iri(self.vocabulary.insert(super::RDF_TYPE)))
98						}
99						crate::quad::PropertyRef::Ref(r) => match r.try_into() {
100							Ok(r) => Cow::Borrowed(r),
101							Err(_) => continue,
102						},
103					};
104
105					if !self.produce_generalized_rdf && (*rdf_property).is_blank() {
106						// Skip gRDF quad.
107						continue;
108					}
109
110					if let Some(compound_value) =
111						object.rdf_value_with(self.vocabulary, self.generator, self.rdf_direction)
112					{
113						if let Some(rdf_value_triples) = compound_value.triples {
114							self.compound_value = Some(Compound {
115								graph: rdf_graph,
116								triples: rdf_value_triples,
117							});
118						}
119
120						break Some(rdf_types::Quad(
121							Cow::Borrowed(rdf_subject),
122							rdf_property,
123							compound_value.value,
124							rdf_graph,
125						));
126					}
127				}
128				None => break None,
129			}
130		}
131	}
132}
133
134/// Iterator over the RDF Quads of a JSON-LD document where borrowed values are
135/// cloned.
136pub struct ClonedQuads<'a, N: Vocabulary, G: Generator<N>> {
137	inner: Quads<'a, N, G>,
138}
139
140impl<'a, N: Vocabulary + IriVocabularyMut, G: Generator<N>> Iterator for ClonedQuads<'a, N, G>
141where
142	N::Iri: Clone,
143	N::BlankId: Clone,
144	N::Literal: Clone,
145	N: LiteralVocabularyMut,
146{
147	type Item = Quad<N::Iri, N::BlankId, N::Literal>;
148
149	fn next(&mut self) -> Option<Self::Item> {
150		self.inner.next().map(|rdf_types::Quad(s, p, o, g)| {
151			rdf_types::Quad(s.into_owned(), p.into_owned(), o, g.cloned())
152		})
153	}
154}
155
156pub trait RdfQuads<T, B> {
157	fn rdf_quads_full<'a, V: Vocabulary<Iri = T, BlankId = B>, G: Generator<V>>(
158		&'a self,
159		vocabulary: &'a mut V,
160		generator: &'a mut G,
161		rdf_direction: Option<RdfDirection>,
162		produce_generalized_rdf: bool,
163	) -> Quads<'a, V, G>;
164
165	fn rdf_quads_with<'a, V: Vocabulary<Iri = T, BlankId = B>, G: Generator<V>>(
166		&'a self,
167		vocabulary: &'a mut V,
168		generator: &'a mut G,
169		rdf_direction: Option<RdfDirection>,
170	) -> Quads<'a, V, G> {
171		self.rdf_quads_full(vocabulary, generator, rdf_direction, false)
172	}
173
174	fn rdf_quads<'a, G: Generator>(
175		&'a self,
176		generator: &'a mut G,
177		rdf_direction: Option<RdfDirection>,
178	) -> Quads<'a, (), G>
179	where
180		(): Vocabulary<Iri = T, BlankId = B>,
181	{
182		self.rdf_quads_with(
183			rdf_types::vocabulary::no_vocabulary_mut(),
184			generator,
185			rdf_direction,
186		)
187	}
188}
189
190impl<T, B> RdfQuads<T, B> for ExpandedDocument<T, B> {
191	fn rdf_quads_full<'a, V: Vocabulary<Iri = T, BlankId = B>, G: Generator<V>>(
192		&'a self,
193		vocabulary: &'a mut V,
194		generator: &'a mut G,
195		rdf_direction: Option<RdfDirection>,
196		produce_generalized_rdf: bool,
197	) -> Quads<'a, V, G> {
198		Quads {
199			vocabulary,
200			generator,
201			rdf_direction,
202			compound_value: None,
203			quads: self.quads(),
204			produce_generalized_rdf,
205		}
206	}
207}
208
209impl<T, B> RdfQuads<T, B> for FlattenedDocument<T, B> {
210	fn rdf_quads_full<'a, V: Vocabulary<Iri = T, BlankId = B>, G: Generator<V>>(
211		&'a self,
212		vocabulary: &'a mut V,
213		generator: &'a mut G,
214		rdf_direction: Option<RdfDirection>,
215		produce_generalized_rdf: bool,
216	) -> Quads<'a, V, G> {
217		Quads {
218			vocabulary,
219			generator,
220			rdf_direction,
221			compound_value: None,
222			quads: self.quads(),
223			produce_generalized_rdf,
224		}
225	}
226}
227
228impl<T: Eq + Hash, B: Eq + Hash> RdfQuads<T, B> for NodeMap<T, B> {
229	fn rdf_quads_full<'a, V: Vocabulary<Iri = T, BlankId = B>, G: Generator<V>>(
230		&'a self,
231		vocabulary: &'a mut V,
232		generator: &'a mut G,
233		rdf_direction: Option<RdfDirection>,
234		produce_generalized_rdf: bool,
235	) -> Quads<'a, V, G> {
236		Quads {
237			vocabulary,
238			generator,
239			rdf_direction,
240			compound_value: None,
241			quads: self.quads(),
242			produce_generalized_rdf,
243		}
244	}
245}