1use std::str::FromStr;
2
3use crate::{object::value, Direction, Id, Indexed, IndexedObject, Node, Object, ValidId};
4use iref::{Iri, IriBuf};
5use json_syntax::Print;
6use langtag::LangTagBuf;
7use rdf_types::{
8 vocabulary::{IriVocabularyMut, LiteralVocabularyMut},
9 Generator, Literal, Vocabulary,
10};
11use smallvec::SmallVec;
12use static_iref::iri;
13
14mod quad;
15pub use quad::*;
16
17pub const RDF_TYPE: &Iri = iri!("http://www.w3.org/1999/02/22-rdf-syntax-ns#type");
18pub const RDF_FIRST: &Iri = iri!("http://www.w3.org/1999/02/22-rdf-syntax-ns#first");
19pub const RDF_REST: &Iri = iri!("http://www.w3.org/1999/02/22-rdf-syntax-ns#rest");
20pub const RDF_VALUE: &Iri = iri!("http://www.w3.org/1999/02/22-rdf-syntax-ns#value");
21pub const RDF_DIRECTION: &Iri = iri!("http://www.w3.org/1999/02/22-rdf-syntax-ns#direction");
22pub const RDF_JSON: &Iri = iri!("http://www.w3.org/1999/02/22-rdf-syntax-ns#JSON");
23pub const RDF_NIL: &Iri = iri!("http://www.w3.org/1999/02/22-rdf-syntax-ns#nil");
25
26pub const XSD_BOOLEAN: &Iri = iri!("http://www.w3.org/2001/XMLSchema#boolean");
27pub const XSD_INTEGER: &Iri = iri!("http://www.w3.org/2001/XMLSchema#integer");
28pub const XSD_DOUBLE: &Iri = iri!("http://www.w3.org/2001/XMLSchema#double");
29pub const XSD_STRING: &Iri = iri!("http://www.w3.org/2001/XMLSchema#string");
30
31pub type Triple<T, B, L> = rdf_types::Triple<ValidId<T, B>, ValidId<T, B>, Value<T, B, L>>;
33
34impl<T: Clone, B: Clone> Id<T, B> {
35 fn rdf_value<L>(&self) -> Option<Value<T, B, L>> {
36 match self {
37 Id::Valid(id) => Some(Value::Id(id.clone())),
38 Id::Invalid(_) => None,
39 }
40 }
41}
42
43#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
48pub enum RdfDirection {
49 I18nDatatype,
57
58 CompoundLiteral,
68}
69
70#[derive(Debug, Clone)]
71pub struct InvalidRdfDirection(pub String);
72
73impl FromStr for RdfDirection {
74 type Err = InvalidRdfDirection;
75
76 fn from_str(s: &str) -> Result<Self, Self::Err> {
77 match s {
78 "i18n-datatype" => Ok(Self::I18nDatatype),
79 "compound-literal" => Ok(Self::CompoundLiteral),
80 _ => Err(InvalidRdfDirection(s.to_string())),
81 }
82 }
83}
84
85impl<'a> TryFrom<&'a str> for RdfDirection {
86 type Error = InvalidRdfDirection;
87
88 fn try_from(value: &'a str) -> Result<Self, Self::Error> {
89 value.parse()
90 }
91}
92
93pub struct CompoundLiteralTriples<T, B, L> {
96 id: ValidId<T, B>,
98
99 value: Option<Value<T, B, L>>,
101
102 direction: Option<Value<T, B, L>>,
104}
105
106impl<T: Clone, B: Clone, L: Clone> CompoundLiteralTriples<T, B, L> {
107 fn next(&mut self, vocabulary: &mut impl IriVocabularyMut<Iri = T>) -> Option<Triple<T, B, L>> {
108 if let Some(value) = self.value.take() {
109 return Some(rdf_types::Triple(
110 self.id.clone(),
111 ValidId::Iri(vocabulary.insert(RDF_VALUE)),
112 value,
113 ));
114 }
115
116 if let Some(direction) = self.direction.take() {
117 return Some(rdf_types::Triple(
118 self.id.clone(),
119 ValidId::Iri(vocabulary.insert(RDF_DIRECTION)),
120 direction,
121 ));
122 }
123
124 None
125 }
126}
127
128pub struct CompoundLiteral<T, B, L> {
130 value: Value<T, B, L>,
131 triples: Option<CompoundLiteralTriples<T, B, L>>,
132}
133
134impl<T: Clone> crate::object::Value<T> {
135 fn rdf_value_with<V, G: Generator<V>>(
136 &self,
137 vocabulary: &mut V,
138 generator: &mut G,
139 rdf_direction: Option<RdfDirection>,
140 ) -> Option<CompoundLiteral<T, V::BlankId, V::Literal>>
141 where
142 V: Vocabulary<Iri = T> + IriVocabularyMut + LiteralVocabularyMut,
143 {
144 match self {
145 Self::Json(json) => {
146 let ty = vocabulary.insert(RDF_JSON);
147 Some(CompoundLiteral {
148 value: Value::Literal(vocabulary.insert_owned_literal(Literal::new(
149 json.compact_print().to_string(),
150 rdf_types::LiteralType::Any(ty),
151 ))),
152 triples: None,
153 })
154 }
155 Self::LangString(lang_string) => {
156 let (string, language, direction) = lang_string.parts();
157
158 let language = match language {
159 Some(language) => match language.as_well_formed() {
160 Some(tag) => Some(tag.to_owned()),
161 None => return None,
162 },
163 None => None,
164 };
165
166 match direction {
167 Some(direction) => match rdf_direction {
168 Some(RdfDirection::I18nDatatype) => {
169 let ty = vocabulary.insert(i18n(language, *direction).as_iri());
170 Some(CompoundLiteral {
171 value: Value::Literal(vocabulary.insert_owned_literal(
172 Literal::new(
173 string.to_string(),
174 rdf_types::LiteralType::Any(ty),
175 ),
176 )),
177 triples: None,
178 })
179 }
180 Some(RdfDirection::CompoundLiteral) => {
181 let id = generator.next(vocabulary);
182 Some(CompoundLiteral {
183 value: id.into_term(),
184 triples: None,
185 })
186 }
187 None => match language {
188 Some(tag) => Some(CompoundLiteral {
189 value: Value::Literal(vocabulary.insert_owned_literal(
190 Literal::new(
191 string.to_string(),
192 rdf_types::LiteralType::LangString(tag),
193 ),
194 )),
195 triples: None,
196 }),
197 None => {
198 let ty = vocabulary.insert(XSD_STRING);
199 Some(CompoundLiteral {
200 value: Value::Literal(vocabulary.insert_owned_literal(
201 Literal::new(
202 string.to_string(),
203 rdf_types::LiteralType::Any(ty),
204 ),
205 )),
206 triples: None,
207 })
208 }
209 },
210 },
211 None => match language {
212 Some(tag) => Some(CompoundLiteral {
213 value: Value::Literal(vocabulary.insert_owned_literal(Literal::new(
214 string.to_string(),
215 rdf_types::LiteralType::LangString(tag),
216 ))),
217 triples: None,
218 }),
219 None => {
220 let ty = vocabulary.insert(XSD_STRING);
221 Some(CompoundLiteral {
222 value: Value::Literal(vocabulary.insert_owned_literal(
223 Literal::new(
224 string.to_string(),
225 rdf_types::LiteralType::Any(ty),
226 ),
227 )),
228 triples: None,
229 })
230 }
231 },
232 }
233 }
234 Self::Literal(lit, ty) => {
235 let (rdf_lit, prefered_rdf_ty) = match lit {
236 value::Literal::Boolean(b) => {
237 let lit = if *b {
238 "true".to_string()
239 } else {
240 "false".to_string()
241 };
242
243 (lit, Some(vocabulary.insert(XSD_BOOLEAN)))
244 }
245 value::Literal::Null => ("null".to_string(), None),
246 value::Literal::Number(n) => {
247 if n.is_i64()
248 && !ty
249 .as_ref()
250 .map(|t| vocabulary.iri(t).unwrap() == XSD_DOUBLE)
251 .unwrap_or(false)
252 {
253 (n.to_string(), Some(vocabulary.insert(XSD_INTEGER)))
254 } else {
255 (
256 pretty_dtoa::dtoa(n.as_f64_lossy(), XSD_CANONICAL_FLOAT),
257 Some(vocabulary.insert(XSD_DOUBLE)),
258 )
259 }
260 }
261 value::Literal::String(s) => (s.to_string(), None),
262 };
263
264 let rdf_ty = match ty {
265 Some(id) => Some(id.clone()),
266 None => prefered_rdf_ty,
267 };
268
269 Some(CompoundLiteral {
270 value: match rdf_ty {
271 Some(ty) => Value::Literal(vocabulary.insert_owned_literal(Literal::new(
272 rdf_lit,
273 rdf_types::LiteralType::Any(ty),
274 ))),
275 None => {
276 let ty = vocabulary.insert(XSD_STRING);
277 Value::Literal(vocabulary.insert_owned_literal(Literal::new(
278 rdf_lit,
279 rdf_types::LiteralType::Any(ty),
280 )))
281 }
282 },
283 triples: None,
284 })
285 }
286 }
287 }
288}
289
290const XSD_CANONICAL_FLOAT: pretty_dtoa::FmtFloatConfig = pretty_dtoa::FmtFloatConfig::default()
292 .force_e_notation()
293 .capitalize_e(true);
294
295impl<T: Clone, B: Clone> Node<T, B> {
296 fn rdf_value<L>(&self) -> Option<Value<T, B, L>> {
297 self.id.as_ref().and_then(Id::rdf_value)
298 }
299}
300
301impl<T: Clone, B: Clone> Object<T, B> {
302 fn rdf_value_with<V, G: Generator<V>>(
303 &self,
304 vocabulary: &mut V,
305 generator: &mut G,
306 rdf_direction: Option<RdfDirection>,
307 ) -> Option<CompoundValue<T, B, V::Literal>>
308 where
309 V: Vocabulary<Iri = T, BlankId = B> + IriVocabularyMut + LiteralVocabularyMut,
310 {
311 match self {
312 Self::Value(value) => value
313 .rdf_value_with(vocabulary, generator, rdf_direction)
314 .map(|compound_value| CompoundValue {
315 value: compound_value.value,
316 triples: compound_value.triples.map(CompoundValueTriples::literal),
317 }),
318 Self::Node(node) => node.rdf_value().map(|value| CompoundValue {
319 value,
320 triples: None,
321 }),
322 Self::List(list) => {
323 if list.is_empty() {
324 Some(CompoundValue {
325 value: Value::Id(ValidId::Iri(vocabulary.insert(RDF_NIL))),
326 triples: None,
327 })
328 } else {
329 let id = generator.next(vocabulary);
330 Some(CompoundValue {
331 value: Clone::clone(&id).into_term(),
332 triples: Some(CompoundValueTriples::List(ListTriples::new(
333 list.as_slice(),
334 id,
335 ))),
336 })
337 }
338 }
339 }
340 }
341}
342
343pub struct CompoundValue<'a, T, B, L> {
344 value: Value<T, B, L>,
345 triples: Option<CompoundValueTriples<'a, T, B, L>>,
346}
347
348impl<'a, T: Clone, B: Clone> crate::quad::ObjectRef<'a, T, B> {
349 pub fn rdf_value_with<V, G: Generator<V>>(
350 &self,
351 vocabulary: &mut V,
352 generator: &mut G,
353 rdf_direction: Option<RdfDirection>,
354 ) -> Option<CompoundValue<'a, T, B, V::Literal>>
355 where
356 V: Vocabulary<Iri = T, BlankId = B> + IriVocabularyMut + LiteralVocabularyMut,
357 {
358 match self {
359 Self::Object(object) => object.rdf_value_with(vocabulary, generator, rdf_direction),
360 Self::Node(node) => node.rdf_value().map(|value| CompoundValue {
361 value,
362 triples: None,
363 }),
364 Self::Ref(r) => r.rdf_value().map(|value| CompoundValue {
365 value,
366 triples: None,
367 }),
368 }
369 }
370}
371
372enum ListItemTriples<'a, T, B, L> {
373 NestedList(NestedListTriples<'a, T, B>),
374 CompoundLiteral(Box<CompoundLiteralTriples<T, B, L>>),
375}
376
377struct NestedListTriples<'a, T, B> {
378 head_ref: Option<ValidId<T, B>>,
379 previous: Option<ValidId<T, B>>,
380 iter: std::slice::Iter<'a, IndexedObject<T, B>>,
381}
382
383struct ListNode<'a, 'i, T, B> {
384 id: &'i ValidId<T, B>,
385 object: &'a Indexed<Object<T, B>>,
386}
387
388impl<'a, T, B> NestedListTriples<'a, T, B> {
389 fn new(list: &'a [IndexedObject<T, B>], head_ref: ValidId<T, B>) -> Self {
390 Self {
391 head_ref: Some(head_ref),
392 previous: None,
393 iter: list.iter(),
394 }
395 }
396
397 fn previous(&self) -> Option<&ValidId<T, B>> {
398 self.previous.as_ref()
399 }
400
401 fn next<V: Vocabulary<Iri = T, BlankId = B>, G: Generator<V>>(
405 &mut self,
406 vocabulary: &mut V,
407 generator: &mut G,
408 ) -> Option<ListNode<'a, '_, T, B>> {
409 if let Some(next) = self.iter.next() {
410 let id = match self.head_ref.take() {
411 Some(id) => id,
412 None => generator.next(vocabulary),
413 };
414
415 self.previous = Some(id);
416 Some(ListNode {
417 object: next,
418 id: self.previous.as_ref().unwrap(),
419 })
420 } else {
421 None
422 }
423 }
424}
425
426pub enum CompoundValueTriples<'a, T, B, L> {
427 Literal(Box<CompoundLiteralTriples<T, B, L>>),
428 List(ListTriples<'a, T, B, L>),
429}
430
431impl<'a, T, B, L> CompoundValueTriples<'a, T, B, L> {
432 pub fn literal(l: CompoundLiteralTriples<T, B, L>) -> Self {
433 Self::Literal(Box::new(l))
434 }
435
436 pub fn with<'n, V: Vocabulary<Iri = T, BlankId = B, Literal = L>, G: Generator<V>>(
437 self,
438 vocabulary: &'n mut V,
439 generator: G,
440 rdf_direction: Option<RdfDirection>,
441 ) -> CompoundValueTriplesWith<'a, 'n, V, G> {
442 CompoundValueTriplesWith {
443 vocabulary,
444 generator,
445 rdf_direction,
446 inner: self,
447 }
448 }
449
450 pub fn next<V, G: Generator<V>>(
451 &mut self,
452 vocabulary: &mut V,
453 generator: &mut G,
454 rdf_direction: Option<RdfDirection>,
455 ) -> Option<Triple<T, B, L>>
456 where
457 T: Clone,
458 B: Clone,
459 L: Clone,
460 V: Vocabulary<Iri = T, BlankId = B, Literal = L> + IriVocabularyMut + LiteralVocabularyMut,
461 {
462 match self {
463 Self::Literal(l) => l.next(vocabulary),
464 Self::List(l) => l.next(vocabulary, generator, rdf_direction),
465 }
466 }
467}
468
469pub struct CompoundValueTriplesWith<'a, 'n, N: Vocabulary, G: Generator<N>> {
470 vocabulary: &'n mut N,
471 generator: G,
472 rdf_direction: Option<RdfDirection>,
473 inner: CompoundValueTriples<'a, N::Iri, N::BlankId, N::Literal>,
474}
475
476impl<'a, 'n, N: Vocabulary + IriVocabularyMut, G: Generator<N>> Iterator
477 for CompoundValueTriplesWith<'a, 'n, N, G>
478where
479 N::Iri: AsRef<Iri> + Clone,
480 N::BlankId: Clone,
481 N::Literal: Clone,
482 N: LiteralVocabularyMut,
483{
484 type Item = Triple<N::Iri, N::BlankId, N::Literal>;
485
486 fn next(&mut self) -> Option<Self::Item> {
487 self.inner
488 .next(self.vocabulary, &mut self.generator, self.rdf_direction)
489 }
490}
491
492pub struct ListTriples<'a, T, B, L> {
496 stack: SmallVec<[ListItemTriples<'a, T, B, L>; 2]>,
497 pending: Option<Triple<T, B, L>>,
498}
499
500impl<'a, T, B, L> ListTriples<'a, T, B, L> {
501 pub fn new(list: &'a [IndexedObject<T, B>], head_ref: ValidId<T, B>) -> Self {
502 let mut stack = SmallVec::new();
503 stack.push(ListItemTriples::NestedList(NestedListTriples::new(
504 list, head_ref,
505 )));
506
507 Self {
508 stack,
509 pending: None,
510 }
511 }
512
513 pub fn with<'n, V: Vocabulary<Iri = T, BlankId = B, Literal = L>, G: Generator<V>>(
514 self,
515 vocabulary: &'n mut V,
516 generator: G,
517 rdf_direction: Option<RdfDirection>,
518 ) -> ListTriplesWith<'a, 'n, V, G> {
519 ListTriplesWith {
520 vocabulary,
521 generator,
522 rdf_direction,
523 inner: self,
524 }
525 }
526
527 pub fn next<V, G: Generator<V>>(
528 &mut self,
529 vocabulary: &mut V,
530 generator: &mut G,
531 rdf_direction: Option<RdfDirection>,
532 ) -> Option<Triple<T, B, L>>
533 where
534 T: Clone,
535 B: Clone,
536 L: Clone,
537 V: Vocabulary<Iri = T, BlankId = B, Literal = L> + IriVocabularyMut + LiteralVocabularyMut,
538 {
539 loop {
540 if let Some(pending) = self.pending.take() {
541 break Some(pending);
542 }
543
544 match self.stack.last_mut() {
545 Some(ListItemTriples::CompoundLiteral(lit)) => match lit.next(vocabulary) {
546 Some(triple) => break Some(triple),
547 None => {
548 self.stack.pop();
549 }
550 },
551 Some(ListItemTriples::NestedList(list)) => {
552 let previous = list.previous().cloned();
553 match list.next(vocabulary, generator) {
554 Some(node) => {
555 if let Some(compound_value) =
556 node.object
557 .rdf_value_with(vocabulary, generator, rdf_direction)
558 {
559 let id = node.id.clone();
560
561 if let Some(compound_triples) = compound_value.triples {
562 match compound_triples {
563 CompoundValueTriples::List(list) => {
564 self.stack.extend(list.stack)
565 }
566 CompoundValueTriples::Literal(lit) => {
567 self.stack.push(ListItemTriples::CompoundLiteral(lit))
568 }
569 }
570 }
571
572 self.pending = Some(rdf_types::Triple(
573 id.clone(),
574 ValidId::Iri(vocabulary.insert(RDF_FIRST)),
575 compound_value.value,
576 ));
577
578 if let Some(previous_id) = previous {
579 break Some(rdf_types::Triple(
580 previous_id,
581 ValidId::Iri(vocabulary.insert(RDF_REST)),
582 id.into_term(),
583 ));
584 }
585 }
586 }
587 None => {
588 self.stack.pop();
589 if let Some(previous_id) = previous {
590 break Some(rdf_types::Triple(
591 previous_id,
592 ValidId::Iri(vocabulary.insert(RDF_REST)),
593 Value::Id(ValidId::Iri(vocabulary.insert(RDF_NIL))),
594 ));
595 }
596 }
597 }
598 }
599 None => break None,
600 }
601 }
602 }
603}
604
605pub struct ListTriplesWith<'a, 'n, V: Vocabulary, G: Generator<V>> {
606 vocabulary: &'n mut V,
607 generator: G,
608 rdf_direction: Option<RdfDirection>,
609 inner: ListTriples<'a, V::Iri, V::BlankId, V::Literal>,
610}
611
612impl<'a, 'n, N: Vocabulary + IriVocabularyMut, G: Generator<N>> Iterator
613 for ListTriplesWith<'a, 'n, N, G>
614where
615 N::Iri: AsRef<Iri> + Clone,
616 N::BlankId: Clone,
617 N::Literal: Clone,
618 N: LiteralVocabularyMut,
619{
620 type Item = Triple<N::Iri, N::BlankId, N::Literal>;
621
622 fn next(&mut self) -> Option<Self::Item> {
623 self.inner
624 .next(self.vocabulary, &mut self.generator, self.rdf_direction)
625 }
626}
627
628fn i18n(language: Option<LangTagBuf>, direction: Direction) -> IriBuf {
629 let iri = match &language {
630 Some(language) => format!("https://www.w3.org/ns/i18n#{language}_{direction}"),
631 None => format!("https://www.w3.org/ns/i18n#{direction}"),
632 };
633
634 IriBuf::new(iri).unwrap()
635}
636
637pub type Value<T, B, L> = rdf_types::Object<ValidId<T, B>, L>;