1use super::{RDF_DIRECTION, RDF_FIRST, RDF_JSON, RDF_NIL, RDF_REST, RDF_VALUE, RdfDirection, XSD_BOOLEAN, XSD_DOUBLE, XSD_INTEGER, XSD_STRING};
2use crate::{Direction, Id, Indexed, IndexedObject, Node, Object, ValidId, object::value};
3use iri_rs::IriBuf;
4use jstrict::Print;
5use langtag::LangTagBuf;
6use rdfx::{
7 Literal,
8 LocalGenerator,
9 vocabulary::{IriVocabularyMut, Vocabulary, VocabularyMut},
10};
11use smallvec::SmallVec;
12
13pub type Triple<T, B, L> = rdfx::GeneralizedTriple<ValidId<T, B>, ValidId<T, B>, Value<T, B, L>>;
15
16fn static_datatype(iri: iri_rs::Iri<&'static str>) -> rdfx::Datatype {
20 rdfx::Datatype::new(IriBuf::from(iri)).unwrap_or_else(|_| rdfx::Datatype::xsd_string())
21}
22
23fn datatype_of<V: rdfx::vocabulary::IriVocabulary>(vocabulary: &V, iri: &V::Iri) -> Option<rdfx::Datatype> {
29 let buf = IriBuf::from(vocabulary.iri(iri)?);
30 rdfx::Datatype::new(buf).ok()
31}
32
33impl<T: Clone, B: Clone> Id<T, B> {
34 fn rdf_value<L>(&self) -> Option<Value<T, B, L>> {
35 match self {
36 Id::Valid(id) => Some(Value::Id(id.clone())),
37 Id::Invalid(_) => None,
38 }
39 }
40}
41
42pub struct CompoundLiteralTriples<T, B, L> {
45 id: ValidId<T, B>,
47
48 value: Option<Value<T, B, L>>,
50
51 direction: Option<Value<T, B, L>>,
53}
54
55impl<T: Clone, B: Clone, L: Clone> CompoundLiteralTriples<T, B, L> {
56 fn next(&mut self, vocabulary: &mut impl IriVocabularyMut<Iri = T>) -> Option<Triple<T, B, L>> {
57 if let Some(value) = self.value.take() {
58 return Some(rdfx::GeneralizedTriple(self.id.clone(), ValidId::Iri(vocabulary.insert(RDF_VALUE)), value));
59 }
60
61 if let Some(direction) = self.direction.take() {
62 return Some(rdfx::GeneralizedTriple(
63 self.id.clone(),
64 ValidId::Iri(vocabulary.insert(RDF_DIRECTION)),
65 direction,
66 ));
67 }
68
69 None
70 }
71}
72
73pub struct CompoundLiteral<T, B, L> {
75 value: Value<T, B, L>,
76 triples: Option<CompoundLiteralTriples<T, B, L>>,
77}
78
79impl<T: Clone> crate::object::Value<T> {
80 fn rdf_value_with<V, G: LocalGenerator>(
81 &self,
82 vocabulary: &mut V,
83 generator: &mut G,
84 rdf_direction: Option<RdfDirection>,
85 ) -> Option<CompoundLiteral<T, V::BlankId, V::Literal>>
86 where
87 V: Vocabulary<Iri = T> + VocabularyMut,
88 {
89 match self {
90 Self::Json(json) => Some(CompoundLiteral {
91 value: Value::Literal(vocabulary.insert_owned_literal(Literal::new(
92 json.compact_print().to_string(),
93 rdfx::LiteralType::Any(static_datatype(RDF_JSON)),
94 ))),
95 triples: None,
96 }),
97 Self::LangString(lang_string) => {
98 let (string, language, direction) = lang_string.parts();
99
100 let language = match language {
101 Some(language) => Some(language.as_well_formed()?.to_owned()),
104 None => None,
105 };
106
107 match direction {
108 Some(direction) => match rdf_direction {
109 Some(RdfDirection::I18nDatatype) => {
110 let ty = rdfx::Datatype::new(i18n(language.as_ref(), *direction)).unwrap_or_else(|_| rdfx::Datatype::xsd_string());
113 Some(CompoundLiteral {
114 value: Value::Literal(vocabulary.insert_owned_literal(Literal::new(string.to_string(), rdfx::LiteralType::Any(ty)))),
115 triples: None,
116 })
117 }
118 Some(RdfDirection::CompoundLiteral) => {
119 let id = crate::id::generator_next_id(vocabulary, generator).ok()?;
123 Some(CompoundLiteral {
124 value: Value::from_id(id),
125 triples: None,
126 })
127 }
128 None => match language {
129 Some(tag) => Some(CompoundLiteral {
130 value: Value::Literal(vocabulary.insert_owned_literal(Literal::new(string.to_string(), rdfx::LiteralType::LangString(tag)))),
131 triples: None,
132 }),
133 None => Some(CompoundLiteral {
134 value: Value::Literal(
135 vocabulary.insert_owned_literal(Literal::new(string.to_string(), rdfx::LiteralType::Any(static_datatype(XSD_STRING)))),
136 ),
137 triples: None,
138 }),
139 },
140 },
141 None => match language {
142 Some(tag) => Some(CompoundLiteral {
143 value: Value::Literal(vocabulary.insert_owned_literal(Literal::new(string.to_string(), rdfx::LiteralType::LangString(tag)))),
144 triples: None,
145 }),
146 None => Some(CompoundLiteral {
147 value: Value::Literal(
148 vocabulary.insert_owned_literal(Literal::new(string.to_string(), rdfx::LiteralType::Any(static_datatype(XSD_STRING)))),
149 ),
150 triples: None,
151 }),
152 },
153 }
154 }
155 Self::Literal(lit, ty) => {
156 let (rdf_lit, preferred_rdf_ty) = match lit {
157 value::Literal::Boolean(b) => {
158 let lit = if *b { "true".to_string() } else { "false".to_string() };
159
160 (lit, Some(static_datatype(XSD_BOOLEAN)))
161 }
162 value::Literal::Null => ("null".to_string(), None),
163 value::Literal::Number(n) => {
164 if n.is_i64() && ty.as_ref().and_then(|t| vocabulary.iri(t)).is_none_or(|i| i != XSD_DOUBLE) {
165 (n.to_string(), Some(static_datatype(XSD_INTEGER)))
166 } else {
167 (pretty_dtoa::dtoa(n.as_f64_lossy(), XSD_CANONICAL_FLOAT), Some(static_datatype(XSD_DOUBLE)))
168 }
169 }
170 value::Literal::String(s) => (s.to_string(), None),
171 };
172
173 let rdf_ty = match ty {
174 Some(id) => Some(datatype_of(vocabulary, id)?),
179 None => preferred_rdf_ty,
180 };
181
182 Some(CompoundLiteral {
183 value: Value::Literal(vocabulary.insert_owned_literal(Literal::new(
184 rdf_lit,
185 rdfx::LiteralType::Any(rdf_ty.unwrap_or_else(|| static_datatype(XSD_STRING))),
186 ))),
187 triples: None,
188 })
189 }
190 }
191 }
192}
193
194pub(crate) const XSD_CANONICAL_FLOAT: pretty_dtoa::FmtFloatConfig = pretty_dtoa::FmtFloatConfig::default().force_e_notation().capitalize_e(true);
196
197impl<T: Clone, B: Clone> Node<T, B> {
198 fn rdf_value<L>(&self) -> Option<Value<T, B, L>> {
199 self.id.as_ref().and_then(Id::rdf_value)
200 }
201}
202
203impl<T: Clone, B: Clone> Object<T, B> {
204 fn rdf_value_with<V, G: LocalGenerator>(
205 &self,
206 vocabulary: &mut V,
207 generator: &mut G,
208 rdf_direction: Option<RdfDirection>,
209 ) -> Option<CompoundValue<'_, T, B, V::Literal>>
210 where
211 V: Vocabulary<Iri = T, BlankId = B> + VocabularyMut,
212 {
213 match self {
214 Self::Value(value) => value.rdf_value_with(vocabulary, generator, rdf_direction).map(|compound_value| CompoundValue {
215 value: compound_value.value,
216 triples: compound_value.triples.map(CompoundValueTriples::literal),
217 }),
218 Self::Node(node) => node.rdf_value().map(|value| CompoundValue { value, triples: None }),
219 Self::List(list) => {
220 if list.is_empty() {
221 Some(CompoundValue {
222 value: Value::Id(ValidId::Iri(vocabulary.insert(RDF_NIL))),
223 triples: None,
224 })
225 } else {
226 let id = crate::id::generator_next_id(vocabulary, generator).ok()?;
229 Some(CompoundValue {
230 value: Value::from_id(id.clone()),
231 triples: Some(CompoundValueTriples::List(ListTriples::new(list.as_slice(), id))),
232 })
233 }
234 }
235 }
236 }
237}
238
239pub struct CompoundValue<'a, T, B, L> {
241 pub value: Value<T, B, L>,
243 pub triples: Option<CompoundValueTriples<'a, T, B, L>>,
245}
246
247impl<'a, T: Clone, B: Clone> crate::quad::ObjectRef<'a, T, B> {
248 pub fn rdf_value_with<V, G: LocalGenerator>(
251 &self,
252 vocabulary: &mut V,
253 generator: &mut G,
254 rdf_direction: Option<RdfDirection>,
255 ) -> Option<CompoundValue<'a, T, B, V::Literal>>
256 where
257 V: Vocabulary<Iri = T, BlankId = B> + VocabularyMut,
258 {
259 match self {
260 Self::Object(object) => object.rdf_value_with(vocabulary, generator, rdf_direction),
261 Self::Node(node) => node.rdf_value().map(|value| CompoundValue { value, triples: None }),
262 Self::Ref(r) => r.rdf_value().map(|value| CompoundValue { value, triples: None }),
263 }
264 }
265}
266
267enum ListItemTriples<'a, T, B, L> {
268 NestedList(NestedListTriples<'a, T, B>),
269 CompoundLiteral(Box<CompoundLiteralTriples<T, B, L>>),
270}
271
272struct NestedListTriples<'a, T, B> {
273 head_ref: Option<ValidId<T, B>>,
274 previous: Option<ValidId<T, B>>,
275 iter: std::slice::Iter<'a, IndexedObject<T, B>>,
276}
277
278struct ListNode<'a, 'i, T, B> {
279 id: &'i ValidId<T, B>,
280 object: &'a Indexed<Object<T, B>>,
281}
282
283impl<'a, T, B> NestedListTriples<'a, T, B> {
284 fn new(list: &'a [IndexedObject<T, B>], head_ref: ValidId<T, B>) -> Self {
285 Self {
286 head_ref: Some(head_ref),
287 previous: None,
288 iter: list.iter(),
289 }
290 }
291
292 fn previous(&self) -> Option<&ValidId<T, B>> {
293 self.previous.as_ref()
294 }
295
296 fn next<V: VocabularyMut<Iri = T, BlankId = B>, G: LocalGenerator>(&mut self, vocabulary: &mut V, generator: &mut G) -> Option<ListNode<'a, '_, T, B>> {
300 if let Some(next) = self.iter.next() {
301 let id = match self.head_ref.take() {
302 Some(id) => id,
303 None => crate::id::generator_next_id(vocabulary, generator).ok()?,
306 };
307
308 Some(ListNode {
309 object: next,
310 id: self.previous.insert(id),
311 })
312 } else {
313 None
314 }
315 }
316}
317
318pub enum CompoundValueTriples<'a, T, B, L> {
320 Literal(Box<CompoundLiteralTriples<T, B, L>>),
322 List(ListTriples<'a, T, B, L>),
324}
325
326impl<'a, T, B, L> CompoundValueTriples<'a, T, B, L> {
327 pub fn literal(l: CompoundLiteralTriples<T, B, L>) -> Self {
329 Self::Literal(Box::new(l))
330 }
331
332 pub fn with<'n, V: Vocabulary<Iri = T, BlankId = B, Literal = L>, G: LocalGenerator>(
334 self,
335 vocabulary: &'n mut V,
336 generator: G,
337 rdf_direction: Option<RdfDirection>,
338 ) -> CompoundValueTriplesWith<'a, 'n, V, G> {
339 CompoundValueTriplesWith {
340 vocabulary,
341 generator,
342 rdf_direction,
343 inner: self,
344 }
345 }
346
347 pub fn next<V, G: LocalGenerator>(&mut self, vocabulary: &mut V, generator: &mut G, rdf_direction: Option<RdfDirection>) -> Option<Triple<T, B, L>>
349 where
350 T: Clone,
351 B: Clone,
352 L: Clone,
353 V: Vocabulary<Iri = T, BlankId = B, Literal = L> + VocabularyMut,
354 {
355 match self {
356 Self::Literal(l) => l.next(vocabulary),
357 Self::List(l) => l.next(vocabulary, generator, rdf_direction),
358 }
359 }
360}
361
362pub struct CompoundValueTriplesWith<'a, 'n, N: Vocabulary, G: LocalGenerator> {
364 vocabulary: &'n mut N,
365 generator: G,
366 rdf_direction: Option<RdfDirection>,
367 inner: CompoundValueTriples<'a, N::Iri, N::BlankId, N::Literal>,
368}
369
370impl<N: Vocabulary + VocabularyMut, G: LocalGenerator> Iterator for CompoundValueTriplesWith<'_, '_, N, G>
371where
372 N::Iri: Clone,
373 N::BlankId: Clone,
374 N::Literal: Clone,
375{
376 type Item = Triple<N::Iri, N::BlankId, N::Literal>;
377
378 fn next(&mut self) -> Option<Self::Item> {
379 self.inner.next(self.vocabulary, &mut self.generator, self.rdf_direction)
380 }
381}
382
383pub struct ListTriples<'a, T, B, L> {
387 stack: SmallVec<[ListItemTriples<'a, T, B, L>; 2]>,
388 pending: Option<Triple<T, B, L>>,
389}
390
391impl<'a, T, B, L> ListTriples<'a, T, B, L> {
392 pub fn new(list: &'a [IndexedObject<T, B>], head_ref: ValidId<T, B>) -> Self {
394 let mut stack = SmallVec::new();
395 stack.push(ListItemTriples::NestedList(NestedListTriples::new(list, head_ref)));
396
397 Self { stack, pending: None }
398 }
399
400 pub fn with<'n, V: Vocabulary<Iri = T, BlankId = B, Literal = L>, G: LocalGenerator>(
402 self,
403 vocabulary: &'n mut V,
404 generator: G,
405 rdf_direction: Option<RdfDirection>,
406 ) -> ListTriplesWith<'a, 'n, V, G> {
407 ListTriplesWith {
408 vocabulary,
409 generator,
410 rdf_direction,
411 inner: self,
412 }
413 }
414
415 pub fn next<V, G: LocalGenerator>(&mut self, vocabulary: &mut V, generator: &mut G, rdf_direction: Option<RdfDirection>) -> Option<Triple<T, B, L>>
418 where
419 T: Clone,
420 B: Clone,
421 L: Clone,
422 V: Vocabulary<Iri = T, BlankId = B, Literal = L> + VocabularyMut,
423 {
424 loop {
425 if let Some(pending) = self.pending.take() {
426 break Some(pending);
427 }
428
429 match self.stack.last_mut() {
430 Some(ListItemTriples::CompoundLiteral(lit)) => match lit.next(vocabulary) {
431 Some(triple) => break Some(triple),
432 None => {
433 self.stack.pop();
434 }
435 },
436 Some(ListItemTriples::NestedList(list)) => {
437 let previous = list.previous().cloned();
438 if let Some(node) = list.next(vocabulary, generator) {
439 if let Some(compound_value) = node.object.rdf_value_with(vocabulary, generator, rdf_direction) {
440 let id = node.id.clone();
441
442 if let Some(compound_triples) = compound_value.triples {
443 match compound_triples {
444 CompoundValueTriples::List(nested) => self.stack.extend(nested.stack),
445 CompoundValueTriples::Literal(literal) => self.stack.push(ListItemTriples::CompoundLiteral(literal)),
446 }
447 }
448
449 self.pending = Some(rdfx::GeneralizedTriple(
450 id.clone(),
451 ValidId::Iri(vocabulary.insert(RDF_FIRST)),
452 compound_value.value,
453 ));
454
455 if let Some(previous_id) = previous {
456 break Some(rdfx::GeneralizedTriple(
457 previous_id,
458 ValidId::Iri(vocabulary.insert(RDF_REST)),
459 Value::from_id(id),
460 ));
461 }
462 }
463 } else {
464 self.stack.pop();
465 if let Some(previous_id) = previous {
466 break Some(rdfx::GeneralizedTriple(
467 previous_id,
468 ValidId::Iri(vocabulary.insert(RDF_REST)),
469 Value::Id(ValidId::Iri(vocabulary.insert(RDF_NIL))),
470 ));
471 }
472 }
473 }
474 None => break None,
475 }
476 }
477 }
478}
479
480pub struct ListTriplesWith<'a, 'n, V: Vocabulary, G: LocalGenerator> {
482 vocabulary: &'n mut V,
483 generator: G,
484 rdf_direction: Option<RdfDirection>,
485 inner: ListTriples<'a, V::Iri, V::BlankId, V::Literal>,
486}
487
488impl<N: Vocabulary + VocabularyMut, G: LocalGenerator> Iterator for ListTriplesWith<'_, '_, N, G>
489where
490 N::Iri: Clone,
491 N::BlankId: Clone,
492 N::Literal: Clone,
493{
494 type Item = Triple<N::Iri, N::BlankId, N::Literal>;
495
496 fn next(&mut self) -> Option<Self::Item> {
497 self.inner.next(self.vocabulary, &mut self.generator, self.rdf_direction)
498 }
499}
500
501fn i18n(language: Option<&LangTagBuf>, direction: Direction) -> IriBuf {
502 let iri = match language {
503 Some(language) => format!("https://www.w3.org/ns/i18n#{language}_{direction}"),
504 None => format!("https://www.w3.org/ns/i18n#{direction}"),
505 };
506
507 IriBuf::new(iri).unwrap_or_else(|_| IriBuf::from(iri_rs::iri!("https://www.w3.org/ns/i18n#")))
510}
511
512#[derive(Debug, Clone, PartialEq, Eq, Hash)]
514pub enum Value<T, B, L> {
515 Id(ValidId<T, B>),
517 Literal(L),
519}
520
521impl<T, B, L> Value<T, B, L> {
522 pub fn from_id(id: ValidId<T, B>) -> Self {
524 Self::Id(id)
525 }
526}