1use rio_api::formatter::{QuadsFormatter, TriplesFormatter};
5use rio_api::model::{
6 BlankNode, GraphName as RioGraphName, Literal, NamedNode, Quad as RioQuad, Subject,
7 Term as RioTerm, Triple as RioTriple,
8};
9use sophia_api::ns::xsd;
10use sophia_api::quad::Quad;
11use sophia_api::source::{QuadSource, StreamResult, TripleSource};
12use sophia_api::term::{FromTerm, SimpleTerm};
13use sophia_api::triple::Triple;
14
15pub fn rio_format_triples<TF, TS>(
19 tf: &mut TF,
20 mut triples: TS,
21) -> StreamResult<(), TS::Error, TF::Error>
22where
23 TF: TriplesFormatter,
24 TS: TripleSource,
25{
26 triples.try_for_each_triple(|t| {
27 let t = t.to_spo().map(SimpleTerm::from_term);
28 match convert_triple(&t, Empty).head() {
29 None => Ok(()),
30 Some(head) => tf.format(head),
31 }
32 })
33}
34
35pub fn rio_format_quads<QF, QS>(
39 qf: &mut QF,
40 mut quads: QS,
41) -> StreamResult<(), QS::Error, QF::Error>
42where
43 QF: QuadsFormatter,
44 QS: QuadSource,
45{
46 quads.try_for_each_quad(|q| {
47 let (t, g) = q.to_spog();
48 let t = t.map(SimpleTerm::from_term);
49 let g = g.map(SimpleTerm::from_term);
50 let graph_name: Option<RioGraphName> = match &g {
51 None => None,
52 Some(SimpleTerm::Iri(iri)) => Some(NamedNode { iri }.into()),
53 Some(SimpleTerm::BlankNode(id)) => Some(BlankNode { id }.into()),
54 _ => {
55 return Ok(());
56 }
57 };
58 match convert_triple(&t, Empty).head() {
59 None => Ok(()),
60 Some(RioTriple {
61 subject,
62 predicate,
63 object,
64 }) => {
65 let q = RioQuad {
66 subject: *subject,
67 predicate: *predicate,
68 object: *object,
69 graph_name,
70 };
71 qf.format(&q)
72 }
73 }
74 })
75}
76
77fn convert_triple<'a>(
80 t: &'a [SimpleTerm<'a>; 3],
81 mut stack: Stack<RioTriple<'a>>,
82) -> Stack<RioTriple<'a>> {
83 let subject = match t.s() {
84 SimpleTerm::Iri(iri) => NamedNode { iri }.into(),
85 SimpleTerm::BlankNode(id) => BlankNode { id }.into(),
86 SimpleTerm::Triple(triple) => {
87 stack = convert_triple(triple, stack);
88 match unsafe { stack.head2() } {
90 Some(t) => Subject::Triple(t),
91 None => {
92 return Empty;
93 }
94 }
95 }
96 _ => {
97 return Empty;
98 }
99 };
100 let predicate = match t.p() {
101 SimpleTerm::Iri(iri) => NamedNode { iri },
102 _ => {
103 return Empty;
104 }
105 };
106 let object = match t.o() {
107 SimpleTerm::Iri(iri) => NamedNode { iri }.into(),
108 SimpleTerm::BlankNode(id) => BlankNode { id }.into(),
109 SimpleTerm::LiteralDatatype(value, iri) if xsd::string == iri => {
110 Literal::Simple { value }.into()
111 }
112 SimpleTerm::LiteralDatatype(value, iri) => Literal::Typed {
113 value,
114 datatype: NamedNode { iri },
115 }
116 .into(),
117 SimpleTerm::LiteralLanguage(value, language) => {
118 Literal::LanguageTaggedString { value, language }.into()
119 }
120 SimpleTerm::Triple(triple) => {
121 stack = convert_triple(triple, stack);
122 match unsafe { stack.head2() } {
124 Some(t) => RioTerm::Triple(t),
125 None => {
126 return Empty;
127 }
128 }
129 }
130 _ => {
131 return Empty;
132 }
133 };
134 Stack::Node(Box::new((
135 RioTriple {
136 subject,
137 predicate,
138 object,
139 },
140 stack,
141 )))
142}
143
144enum Stack<T> {
145 Empty,
146 Node(Box<(T, Stack<T>)>),
147}
148use Stack::*;
149impl<T> Stack<T> {
150 fn head(&self) -> Option<&T> {
152 match self {
153 Empty => None,
154 Node(b) => Some(&b.0),
155 }
156 }
157 unsafe fn head2<'a>(&self) -> Option<&'a T>
168 where
169 Self: 'a,
170 T: 'a,
171 {
172 self.head().map(|h| std::mem::transmute(h))
173 }
174}