1use super::*;
2use crate::ns::rdf;
3use crate::triple::Triple;
4
5lazy_static::lazy_static! {
6 static ref RDF_LANG_STRING: Box<str> = rdf::langString.iri().unwrap().unwrap().into();
7 static ref RDF_DIR_LANG_STRING: Box<str> = rdf::dirLangString.iri().unwrap().unwrap().into();
8}
9
10#[derive(Clone, Debug)]
12pub enum SimpleTerm<'a> {
13 Iri(IriRef<MownStr<'a>>),
15 BlankNode(BnodeId<MownStr<'a>>),
17 LiteralDatatype(MownStr<'a>, IriRef<MownStr<'a>>),
19 LiteralLanguage(MownStr<'a>, LanguageTag<MownStr<'a>>, Option<BaseDirection>),
21 Triple(Box<[Self; 3]>),
23 Variable(VarName<MownStr<'a>>),
25}
26
27use SimpleTerm::*;
28
29impl<'a> Term for SimpleTerm<'a> {
30 type BorrowTerm<'x>
31 = &'x Self
32 where
33 'a: 'x;
34
35 fn kind(&self) -> TermKind {
36 match self {
37 Iri(_) => TermKind::Iri,
38 BlankNode(_) => TermKind::BlankNode,
39 LiteralDatatype(..) | LiteralLanguage(..) => TermKind::Literal,
40 Triple(_) => TermKind::Triple,
41 Variable(_) => TermKind::Variable,
42 }
43 }
44 fn iri(&self) -> Option<IriRef<MownStr<'_>>> {
45 if let Iri(iri) = self {
46 Some(IriRef::new_unchecked(iri.borrowed()))
47 } else {
48 None
49 }
50 }
51 fn bnode_id(&self) -> Option<BnodeId<MownStr<'_>>> {
52 if let BlankNode(bnid) = self {
53 Some(BnodeId::new_unchecked(bnid.borrowed()))
54 } else {
55 None
56 }
57 }
58 fn lexical_form(&self) -> Option<MownStr<'_>> {
59 match self {
60 LiteralDatatype(val, _) | LiteralLanguage(val, _, _) => Some(MownStr::from(&val[..])),
61 _ => None,
62 }
63 }
64 fn datatype(&self) -> Option<IriRef<MownStr<'_>>> {
65 match self {
66 LiteralDatatype(_, iri) => Some(IriRef::new_unchecked(iri.borrowed())),
67 LiteralLanguage(_, _, None) => {
68 Some(IriRef::new_unchecked(MownStr::from_ref(&RDF_LANG_STRING)))
69 }
70 LiteralLanguage(_, _, Some(_)) => Some(IriRef::new_unchecked(MownStr::from_ref(
71 &RDF_DIR_LANG_STRING,
72 ))),
73 _ => None,
74 }
75 }
76 fn language_tag(&self) -> Option<LanguageTag<MownStr<'_>>> {
77 if let LiteralLanguage(_, tag, _) = self {
78 Some(LanguageTag::new_unchecked(MownStr::from_ref(tag)))
79 } else {
80 None
81 }
82 }
83 fn base_direction(&self) -> Option<BaseDirection> {
84 if let LiteralLanguage(_, _, dir) = self {
85 *dir
86 } else {
87 None
88 }
89 }
90 fn variable(&self) -> Option<VarName<MownStr<'_>>> {
91 if let Variable(name) = self {
92 Some(VarName::new_unchecked(MownStr::from_ref(name)))
93 } else {
94 None
95 }
96 }
97 fn triple(&self) -> Option<[Self::BorrowTerm<'_>; 3]> {
98 if let Triple(triple) = self {
99 let [s, p, o] = triple.as_ref();
100 Some([s, p, o])
101 } else {
102 None
103 }
104 }
105 fn to_triple(self) -> Option<[Self; 3]> {
106 if let Triple(triple) = self {
107 Some(*triple)
108 } else {
109 None
110 }
111 }
112 fn borrow_term(&self) -> Self::BorrowTerm<'_> {
113 self
114 }
115}
116
117fn ensure_owned(m: MownStr) -> MownStr<'static> {
118 if m.is_owned() {
119 let m = m.clone();
120 unsafe { std::mem::transmute::<mownstr::MownStr<'_>, mownstr::MownStr<'_>>(m) }
123 } else {
124 m.to_string().into()
125 }
126}
127
128impl FromTerm for SimpleTerm<'static> {
129 fn from_term<T: Term>(term: T) -> Self {
130 match term.kind() {
131 TermKind::Iri => SimpleTerm::Iri(term.iri().unwrap().map_unchecked(ensure_owned)),
132 TermKind::BlankNode => {
133 SimpleTerm::BlankNode(term.bnode_id().unwrap().map_unchecked(ensure_owned))
134 }
135 TermKind::Literal => {
136 let lex = ensure_owned(term.lexical_form().unwrap());
137 if let Some(tag) = term.language_tag() {
138 let tag = tag.map_unchecked(ensure_owned);
139 let dir = term.base_direction();
140 SimpleTerm::LiteralLanguage(lex, tag, dir)
141 } else {
142 let dt = term.datatype().unwrap().map_unchecked(ensure_owned);
143 SimpleTerm::LiteralDatatype(lex, dt)
144 }
145 }
146 TermKind::Triple => {
147 let t = term.triple().unwrap();
148 SimpleTerm::Triple(Box::new([
149 Self::from_term(t.s()),
150 Self::from_term(t.p()),
151 Self::from_term(t.o()),
152 ]))
153 }
154 TermKind::Variable => {
155 SimpleTerm::Variable(term.variable().unwrap().map_unchecked(ensure_owned))
156 }
157 }
158 }
159}
160
161impl TryFromTerm for SimpleTerm<'static> {
162 type Error = std::convert::Infallible;
163
164 fn try_from_term<T: Term>(term: T) -> Result<Self, Self::Error> {
165 Ok(Self::from_term(term))
166 }
167}
168
169impl<'a> SimpleTerm<'a> {
170 pub fn from_term_ref<T>(term: &'a T) -> Self
175 where
176 T: Term + ?Sized,
177 {
178 match term.kind() {
179 TermKind::Iri => SimpleTerm::Iri(term.iri().unwrap()),
180 TermKind::BlankNode => SimpleTerm::BlankNode(term.bnode_id().unwrap()),
181 TermKind::Literal => {
182 let lex = term.lexical_form().unwrap();
183 if let Some(tag) = term.language_tag() {
184 let dir = term.base_direction();
185 SimpleTerm::LiteralLanguage(lex, tag, dir)
186 } else {
187 let dt = term.datatype().unwrap();
188 SimpleTerm::LiteralDatatype(lex, dt)
189 }
190 }
191 TermKind::Triple => {
192 let t = term.triple().unwrap();
193 SimpleTerm::Triple(Box::new([
194 SimpleTerm::<'static>::from_term(t.s()),
195 SimpleTerm::<'static>::from_term(t.p()),
196 SimpleTerm::<'static>::from_term(t.o()),
197 ]))
198 }
199 TermKind::Variable => SimpleTerm::Variable(term.variable().unwrap()),
200 }
201 }
202
203 pub fn from_triple<T: crate::triple::Triple>(triple: T) -> Self {
205 Self::Triple(Box::new([
206 triple.s().into_term(),
207 triple.p().into_term(),
208 triple.o().into_term(),
209 ]))
210 }
211}
212
213impl<T: Term> PartialEq<T> for SimpleTerm<'_> {
214 fn eq(&self, other: &T) -> bool {
215 Term::eq(self, other.borrow_term())
216 }
217}
218
219impl Eq for SimpleTerm<'_> {}
220
221impl std::hash::Hash for SimpleTerm<'_> {
222 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
223 Term::hash(self, state)
224 }
225}
226
227impl<T: Term> PartialOrd<T> for SimpleTerm<'_> {
228 fn partial_cmp(&self, other: &T) -> Option<Ordering> {
229 Some(Term::cmp(self, other.borrow_term()))
230 }
231}
232
233impl Ord for SimpleTerm<'_> {
234 fn cmp(&self, other: &Self) -> Ordering {
235 Term::cmp(self, other)
236 }
237}
238
239#[cfg(test)]
240mod test {
241 use super::*;
242 use crate::ns::xsd;
243
244 #[test]
245 fn iri_from_scratch() {
246 let value = IriRef::new_unchecked(MownStr::from_ref("http://example.org/"));
247 let t = SimpleTerm::Iri(value.clone());
248 assert_consistent_term_impl(&t);
249 assert_eq!(t.borrow_term(), &t);
250 assert_eq!(t.kind(), TermKind::Iri);
251 assert_eq!(t.iri(), Some(value));
252 }
253
254 #[test]
255 fn bnode_from_scratch() {
256 let value = BnodeId::new_unchecked(MownStr::from_ref("b1"));
257 let t = SimpleTerm::BlankNode(value.clone());
258 assert_consistent_term_impl(&t);
259 assert_eq!(t.borrow_term(), &t);
260 assert_eq!(t.kind(), TermKind::BlankNode);
261 assert_eq!(t.bnode_id(), Some(value));
262 }
263
264 #[test]
265 fn literal_dt_from_scratch() {
266 let value = MownStr::from_ref("hello world");
267 let datatype = IriRef::new_unchecked(MownStr::from_ref("http://example.org/"));
268 let t = SimpleTerm::LiteralDatatype(value.clone(), datatype.clone());
269 assert_consistent_term_impl(&t);
270 assert_eq!(t.borrow_term(), &t);
271 assert_eq!(t.kind(), TermKind::Literal);
272 assert_eq!(t.lexical_form(), Some(value));
273 assert_eq!(t.datatype(), Some(datatype));
274 }
275
276 #[test]
277 fn literal_lang_from_scratch() {
278 let value = MownStr::from_ref("hello world");
279 let tag = LanguageTag::new_unchecked(MownStr::from_ref("en-US"));
280 let t = SimpleTerm::LiteralLanguage(value.clone(), tag.clone(), None);
281 assert_consistent_term_impl(&t);
282 assert_eq!(t.borrow_term(), &t);
283 assert_eq!(t.kind(), TermKind::Literal);
284 assert_eq!(t.lexical_form(), Some(value));
285 assert_eq!(t.language_tag(), Some(tag));
286 assert_eq!(t.base_direction(), None);
287 }
288
289 #[test]
290 fn literal_dir_lang_from_scratch() {
291 let value = MownStr::from_ref("hello world");
292 let tag = LanguageTag::new_unchecked(MownStr::from_ref("en-US"));
293 let dir = BaseDirection::Ltr;
294 let t = SimpleTerm::LiteralLanguage(value.clone(), tag.clone(), Some(dir));
295 assert_consistent_term_impl(&t);
296 assert_eq!(t.borrow_term(), &t);
297 assert_eq!(t.kind(), TermKind::Literal);
298 assert_eq!(t.lexical_form(), Some(value));
299 assert_eq!(t.language_tag(), Some(tag));
300 assert_eq!(t.base_direction(), Some(dir));
301 }
302
303 #[test]
304 fn variable_from_scratch() {
305 let value = VarName::new_unchecked(MownStr::from_ref("x"));
306 let t = SimpleTerm::Variable(value.clone());
307 assert_consistent_term_impl(&t);
308 assert_eq!(t.borrow_term(), &t);
309 assert_eq!(t.kind(), TermKind::Variable);
310 assert_eq!(t.variable(), Some(value));
311 }
312
313 #[test]
314 fn triple_from_scratch() {
315 let s: SimpleTerm<'_> = BnodeId::new_unchecked(MownStr::from_ref("s")).into_term();
316 let p: SimpleTerm<'_> = IriRef::new_unchecked(MownStr::from_ref("p")).into_term();
317 let o: SimpleTerm<'_> = "o".into_term();
318 let spo = [s.clone(), p.clone(), o.clone()];
319 let t = SimpleTerm::Triple(Box::new(spo.clone()));
320 assert_consistent_term_impl(&t);
321 assert_eq!(t.borrow_term(), &t);
322 assert_eq!(t.kind(), TermKind::Triple);
323 assert_eq!(t.triple(), Some([&s, &p, &o]));
324 assert_eq!(t.clone().to_triple(), Some(spo.clone()));
325 assert_eq!(t.constituents().collect::<Vec<_>>(), vec![&t, &s, &p, &o]);
326 assert_eq!(
327 t.clone().to_constituents().collect::<Vec<_>>(),
328 t.constituents().cloned().collect::<Vec<_>>()
329 );
330 assert_eq!(t.atoms().collect::<Vec<_>>(), vec![&s, &p, &o]);
331 assert_eq!(
332 t.clone().to_atoms().collect::<Vec<_>>(),
333 Vec::from(spo.clone())
334 );
335 }
336
337 #[test]
338 fn nested_triple_from_scratch() {
339 let s1: SimpleTerm<'_> = BnodeId::new_unchecked(MownStr::from_ref("s")).into_term();
340 let p1: SimpleTerm<'_> = IriRef::new_unchecked(MownStr::from_ref("p")).into_term();
341 let o1: SimpleTerm<'_> = "o".into_term();
342 let spo1 = [s1.clone(), p1.clone(), o1.clone()];
343 let t1 = SimpleTerm::Triple(Box::new(spo1));
344 let s: SimpleTerm<'_> = s1.clone();
345 let p: SimpleTerm<'_> = p1.clone();
346 let o = t1.clone();
347 let spo2 = [s.clone(), p.clone(), o.clone()];
348 let t = SimpleTerm::Triple(Box::new(spo2.clone()));
349 assert_consistent_term_impl(&t);
350 assert_eq!(t.borrow_term(), &t);
351 assert_eq!(t.kind(), TermKind::Triple);
352 assert_eq!(t.triple(), Some([&s, &p, &o]));
353 assert_eq!(t.clone().to_triple(), Some(spo2.clone()));
354 assert_eq!(
355 t.constituents().collect::<Vec<_>>(),
356 vec![&t, &s, &p, &t1, &s1, &p1, &o1]
357 );
358 assert_eq!(
359 t.clone().to_constituents().collect::<Vec<_>>(),
360 t.constituents().cloned().collect::<Vec<_>>()
361 );
362 assert_eq!(t.atoms().collect::<Vec<_>>(), vec![&s, &p, &s1, &p1, &o1]);
363 assert_eq!(
364 t.clone().to_atoms().collect::<Vec<_>>(),
365 t.atoms().cloned().collect::<Vec<_>>()
366 );
367 }
368
369 #[test]
370 fn iri_from_term() {
371 let t: SimpleTerm<'_> = rdf::type_.into_term();
372 assert_consistent_term_impl(&t);
373 assert_eq!(t.kind(), TermKind::Iri);
374 assert_eq!(t.iri(), rdf::type_.iri());
375 }
376
377 #[test]
378 fn literal_from_term() {
379 let t: SimpleTerm<'_> = "hello world".into_term();
380 assert_consistent_term_impl(&t);
381 assert_eq!(t.kind(), TermKind::Literal);
382 assert_eq!(t.lexical_form().unwrap(), "hello world");
383 assert_eq!(t.datatype(), xsd::string.iri());
384
385 let t: SimpleTerm<'_> = 42.into_term();
386 assert_consistent_term_impl(&t);
387 assert_eq!(t.kind(), TermKind::Literal);
388 assert_eq!(t.lexical_form().unwrap(), "42");
389 assert_eq!(t.datatype(), xsd::integer.iri());
390 }
391
392 #[test]
393 fn bnode_from_term() {
394 let b1 = BnodeId::new("b1").unwrap();
395 let t: SimpleTerm<'_> = b1.into_term();
396 assert_consistent_term_impl(&t);
397 assert_eq!(t.kind(), TermKind::BlankNode);
398 assert_eq!(t.bnode_id().unwrap(), b1);
399 }
400
401 #[test]
402 fn triple_from_term() {
403 let s: SimpleTerm<'_> = BnodeId::new_unchecked(MownStr::from_ref("s")).into_term();
404 let p: SimpleTerm<'_> = IriRef::new_unchecked(MownStr::from_ref("p")).into_term();
405 let o: SimpleTerm<'_> = "o".into_term();
406 let spo = [s.clone(), p.clone(), o.clone()];
407 let tr = SimpleTerm::from_triple(spo.spo());
408 let t: SimpleTerm<'_> = tr.into_term();
409 assert_consistent_term_impl(&t);
410 assert_eq!(t.borrow_term(), &t);
411 assert_eq!(t.kind(), TermKind::Triple);
412 assert_eq!(t.triple(), Some([&s, &p, &o]));
413 assert_eq!(t.clone().to_triple(), Some(spo.clone()));
414 assert_eq!(t.constituents().collect::<Vec<_>>(), vec![&t, &s, &p, &o]);
415 assert_eq!(
416 t.clone().to_constituents().collect::<Vec<_>>(),
417 t.constituents().cloned().collect::<Vec<_>>()
418 );
419 assert_eq!(t.atoms().collect::<Vec<_>>(), vec![&s, &p, &o]);
420 assert_eq!(
421 t.clone().to_atoms().collect::<Vec<_>>(),
422 Vec::from(spo.clone())
423 );
424 }
425
426 #[test]
427 fn variable_from_term() {
428 let v1 = VarName::new("v1").unwrap();
429 let t: SimpleTerm<'_> = v1.into_term();
430 assert_consistent_term_impl(&t);
431 assert_eq!(t.kind(), TermKind::Variable);
432 assert_eq!(t.variable().unwrap(), v1);
433 }
434
435 #[test]
436 fn try_from_term() {
437 let t: SimpleTerm<'_> = 42.try_into_term().unwrap();
438 assert_consistent_term_impl(&t);
439 assert_eq!(t.kind(), TermKind::Literal);
440 assert_eq!(t.lexical_form().unwrap(), "42");
441 assert_eq!(t.datatype(), xsd::integer.iri());
442 }
443
444 #[test]
445 fn iri_from_term_ref() {
446 let i = sophia_iri::Iri::new("http://example.com/").unwrap();
447 let t = SimpleTerm::from_term_ref(&i);
448 assert_consistent_term_impl(&t);
449 assert_eq!(t.kind(), TermKind::Iri);
450 assert_eq!(t.iri(), i.iri());
451 assert!(t.iri().unwrap().unwrap().is_borrowed());
452 }
453
454 #[test]
455 fn literal_from_term_ref() {
456 let l = "hello world";
457 let t = SimpleTerm::from_term_ref(&l);
458 assert_consistent_term_impl(&t);
459 assert_eq!(t.kind(), TermKind::Literal);
460 assert_eq!(t.lexical_form().unwrap(), l);
461 assert!(t.lexical_form().unwrap().is_borrowed());
462 }
463
464 #[test]
465 fn bnode_from_term_ref() {
466 let b = BnodeId::new("b1").unwrap();
467 let t = SimpleTerm::from_term_ref(&b);
468 assert_consistent_term_impl(&t);
469 assert_eq!(t.kind(), TermKind::BlankNode);
470 assert_eq!(t.bnode_id().unwrap(), b);
471 assert!(t.bnode_id().unwrap().unwrap().is_borrowed());
472 }
473
474 #[test]
475 fn triple_from_term_ref() {
476 let s: SimpleTerm<'_> = BnodeId::new_unchecked(MownStr::from_ref("s")).into_term();
477 let p: SimpleTerm<'_> = IriRef::new_unchecked(MownStr::from_ref("p")).into_term();
478 let o: SimpleTerm<'_> = "o".into_term();
479 let spo = [s.clone(), p.clone(), o.clone()];
480 let tr = SimpleTerm::from_triple(spo.spo());
481 let t = SimpleTerm::from_term_ref(&tr);
482 assert_consistent_term_impl(&t);
483 assert_eq!(t.kind(), TermKind::Triple);
484 let inner_s = t.to_atoms().next().unwrap();
485 assert!(inner_s.bnode_id().unwrap().unwrap().is_borrowed());
486 }
487
488 #[test]
489 fn variable_from_term_ref() {
490 let v = VarName::new("v1").unwrap();
491 let t = SimpleTerm::from_term_ref(&v);
492 assert_consistent_term_impl(&t);
493 assert_eq!(t.kind(), TermKind::Variable);
494 assert_eq!(t.variable().unwrap(), v);
495 assert!(t.variable().unwrap().unwrap().is_borrowed());
496 }
497}