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
34pub 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 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
134pub 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}