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