1use oxrdf::{
2 BlankNode, Dataset, GraphNameRef, Literal, NamedNode, QuadRef, SubjectRef, Term, TermRef,
3};
4#[cfg(feature = "rdf-star")]
5use oxrdf::{Subject, Triple};
6use oxsdatatypes::{Boolean, DateTime, Decimal, Double, Float, Integer};
7#[cfg(feature = "sep-0002")]
8use oxsdatatypes::{Date, DayTimeDuration, Duration, Time, YearMonthDuration};
9#[cfg(feature = "calendar-ext")]
10use oxsdatatypes::{GDay, GMonth, GMonthDay, GYear, GYearMonth};
11use rustc_hash::FxHashSet;
12use std::convert::Infallible;
13use std::error::Error;
14use std::hash::{Hash, Hasher};
15use std::iter::empty;
16use std::mem::discriminant;
17
18pub trait QueryableDataset: Sized + 'static {
20 type InternalTerm: Clone + Eq + Hash;
26
27 type Error: Error + Send + Sync;
29
30 fn internal_quads_for_pattern(
34 &self,
35 subject: Option<&Self::InternalTerm>,
36 predicate: Option<&Self::InternalTerm>,
37 object: Option<&Self::InternalTerm>,
38 graph_name: Option<Option<&Self::InternalTerm>>,
39 ) -> Box<dyn Iterator<Item = Result<InternalQuad<Self>, Self::Error>>>; fn internal_named_graphs(
43 &self,
44 ) -> Box<dyn Iterator<Item = Result<Self::InternalTerm, Self::Error>>> {
45 let mut error = None;
47 let graph_names = self
48 .internal_quads_for_pattern(None, None, None, None)
49 .filter_map(|r| match r {
50 Ok(r) => Some(r.graph_name?),
51 Err(e) => {
52 error = Some(e);
53 None
54 }
55 })
56 .collect::<FxHashSet<_>>();
57
58 Box::new(
59 error
60 .map(Err)
61 .into_iter()
62 .chain(graph_names.into_iter().map(Ok)),
63 )
64 }
65
66 fn contains_internal_graph_name(
68 &self,
69 graph_name: &Self::InternalTerm,
70 ) -> Result<bool, Self::Error> {
71 Ok(self
72 .internal_quads_for_pattern(None, None, None, Some(Some(graph_name)))
73 .next()
74 .transpose()?
75 .is_some())
76 }
77
78 fn internalize_term(&self, term: Term) -> Result<Self::InternalTerm, Self::Error>;
80
81 fn externalize_term(&self, term: Self::InternalTerm) -> Result<Term, Self::Error>;
83
84 fn externalize_expression_term(
88 &self,
89 term: Self::InternalTerm,
90 ) -> Result<ExpressionTerm, Self::Error> {
91 Ok(self.externalize_term(term)?.into())
92 }
93
94 fn internalize_expression_term(
96 &self,
97 term: ExpressionTerm,
98 ) -> Result<Self::InternalTerm, Self::Error> {
99 self.internalize_term(term.into())
100 }
101
102 fn internal_term_effective_boolean_value(
104 &self,
105 term: Self::InternalTerm,
106 ) -> Result<Option<bool>, Self::Error> {
107 Ok(self
108 .externalize_expression_term(term)?
109 .effective_boolean_value())
110 }
111}
112
113impl QueryableDataset for Dataset {
114 type InternalTerm = Term;
115 type Error = Infallible;
116
117 fn internal_quads_for_pattern(
118 &self,
119 subject: Option<&Term>,
120 predicate: Option<&Term>,
121 object: Option<&Term>,
122 graph_name: Option<Option<&Term>>,
123 ) -> Box<dyn Iterator<Item = Result<InternalQuad<Self>, Infallible>>> {
124 #[allow(clippy::unnecessary_wraps)]
127 fn quad_to_result(quad: QuadRef<'_>) -> Result<InternalQuad<Dataset>, Infallible> {
128 Ok(InternalQuad {
129 subject: quad.subject.into(),
130 predicate: quad.predicate.into(),
131 object: quad.object.into_owned(),
132 graph_name: match quad.graph_name {
133 GraphNameRef::NamedNode(g) => Some(g.into()),
134 GraphNameRef::BlankNode(g) => Some(g.into()),
135 GraphNameRef::DefaultGraph => None,
136 },
137 })
138 }
139
140 let subject = if let Some(subject) = subject {
141 Some(match TermRef::from(subject) {
142 TermRef::NamedNode(s) => SubjectRef::from(s),
143 TermRef::BlankNode(s) => s.into(),
144 TermRef::Literal(_) => return Box::new(empty()),
145 #[cfg(feature = "rdf-star")]
146 TermRef::Triple(s) => s.into(),
147 })
148 } else {
149 None
150 };
151 let predicate = if let Some(predicate) = predicate {
152 if let TermRef::NamedNode(p) = TermRef::from(predicate) {
153 Some(p)
154 } else {
155 return Box::new(empty());
156 }
157 } else {
158 None
159 };
160 let object = object.map(TermRef::from);
161 let graph_name = if let Some(graph_name) = graph_name {
162 Some(if let Some(graph_name) = graph_name {
163 match TermRef::from(graph_name) {
164 TermRef::NamedNode(s) => s.into(),
165 TermRef::BlankNode(s) => s.into(),
166 TermRef::Literal(_) => return Box::new(empty()),
167 #[cfg(feature = "rdf-star")]
168 TermRef::Triple(_) => return Box::new(empty()),
169 }
170 } else {
171 GraphNameRef::DefaultGraph
172 })
173 } else {
174 None
175 };
176 let quads: Vec<_> = if let Some(subject) = subject {
177 self.quads_for_subject(subject)
178 .filter(|q| {
179 predicate.map_or(true, |t| t == q.predicate)
180 && object.map_or(true, |t| t == q.object)
181 && graph_name
182 .map_or_else(|| !q.graph_name.is_default_graph(), |t| t == q.graph_name)
183 })
184 .map(quad_to_result)
185 .collect()
186 } else if let Some(object) = object {
187 self.quads_for_object(object)
188 .filter(|q| {
189 predicate.map_or(true, |t| t == q.predicate)
190 && graph_name
191 .map_or_else(|| !q.graph_name.is_default_graph(), |t| t == q.graph_name)
192 })
193 .map(quad_to_result)
194 .collect()
195 } else if let Some(predicate) = predicate {
196 self.quads_for_predicate(predicate)
197 .filter(|q| {
198 graph_name
199 .map_or_else(|| !q.graph_name.is_default_graph(), |t| t == q.graph_name)
200 })
201 .map(quad_to_result)
202 .collect()
203 } else if let Some(graph_name) = graph_name {
204 self.quads_for_graph_name(graph_name)
205 .map(quad_to_result)
206 .collect()
207 } else {
208 self.iter()
209 .filter(|q| !q.graph_name.is_default_graph())
210 .map(quad_to_result)
211 .collect()
212 };
213 Box::new(quads.into_iter())
214 }
215
216 fn internalize_term(&self, term: Term) -> Result<Term, Infallible> {
217 Ok(term)
218 }
219
220 fn externalize_term(&self, term: Term) -> Result<Term, Infallible> {
221 Ok(term)
222 }
223}
224
225pub struct InternalQuad<D: QueryableDataset> {
226 pub subject: D::InternalTerm,
227 pub predicate: D::InternalTerm,
228 pub object: D::InternalTerm,
229 pub graph_name: Option<D::InternalTerm>,
231}
232
233#[derive(Clone)]
235pub enum ExpressionTerm {
236 NamedNode(NamedNode),
237 BlankNode(BlankNode),
238 StringLiteral(String),
239 LangStringLiteral {
240 value: String,
241 language: String,
242 },
243 BooleanLiteral(Boolean),
244 IntegerLiteral(Integer),
245 DecimalLiteral(Decimal),
246 FloatLiteral(Float),
247 DoubleLiteral(Double),
248 DateTimeLiteral(DateTime),
249 #[cfg(feature = "sep-0002")]
250 DateLiteral(Date),
251 #[cfg(feature = "sep-0002")]
252 TimeLiteral(Time),
253 #[cfg(feature = "calendar-ext")]
254 GYearLiteral(GYear),
255 #[cfg(feature = "calendar-ext")]
256 GYearMonthLiteral(GYearMonth),
257 #[cfg(feature = "calendar-ext")]
258 GMonthLiteral(GMonth),
259 #[cfg(feature = "calendar-ext")]
260 GMonthDayLiteral(GMonthDay),
261 #[cfg(feature = "calendar-ext")]
262 GDayLiteral(GDay),
263 #[cfg(feature = "sep-0002")]
264 DurationLiteral(Duration),
265 #[cfg(feature = "sep-0002")]
266 YearMonthDurationLiteral(YearMonthDuration),
267 #[cfg(feature = "sep-0002")]
268 DayTimeDurationLiteral(DayTimeDuration),
269 OtherTypedLiteral {
270 value: String,
271 datatype: NamedNode,
272 },
273 #[cfg(feature = "rdf-star")]
274 Triple(Box<ExpressionTriple>),
275}
276
277impl PartialEq for ExpressionTerm {
278 #[inline]
279 fn eq(&self, other: &Self) -> bool {
280 discriminant(self) == discriminant(other)
281 && match (self, other) {
282 (Self::NamedNode(l), Self::NamedNode(r)) => l == r,
283 (Self::BlankNode(l), Self::BlankNode(r)) => l == r,
284 (Self::StringLiteral(l), Self::StringLiteral(r)) => l == r,
285 (
286 Self::LangStringLiteral {
287 value: lv,
288 language: ll,
289 },
290 Self::LangStringLiteral {
291 value: rv,
292 language: rl,
293 },
294 ) => lv == rv && ll == rl,
295 (Self::BooleanLiteral(l), Self::BooleanLiteral(r)) => l == r,
296 (Self::IntegerLiteral(l), Self::IntegerLiteral(r)) => l == r,
297 (Self::DecimalLiteral(l), Self::DecimalLiteral(r)) => l == r,
298 (Self::FloatLiteral(l), Self::FloatLiteral(r)) => l.is_identical_with(*r),
299 (Self::DoubleLiteral(l), Self::DoubleLiteral(r)) => l.is_identical_with(*r),
300 (Self::DateTimeLiteral(l), Self::DateTimeLiteral(r)) => l == r,
301 #[cfg(feature = "sep-0002")]
302 (Self::DateLiteral(l), Self::DateLiteral(r)) => l == r,
303 #[cfg(feature = "sep-0002")]
304 (Self::TimeLiteral(l), Self::TimeLiteral(r)) => l == r,
305 #[cfg(feature = "calendar-ext")]
306 (Self::GYearMonthLiteral(l), Self::GYearMonthLiteral(r)) => l == r,
307 #[cfg(feature = "calendar-ext")]
308 (Self::GYearLiteral(l), Self::GYearLiteral(r)) => l == r,
309 #[cfg(feature = "calendar-ext")]
310 (Self::GMonthLiteral(l), Self::GMonthLiteral(r)) => l == r,
311 #[cfg(feature = "calendar-ext")]
312 (Self::GMonthDayLiteral(l), Self::GMonthDayLiteral(r)) => l == r,
313 #[cfg(feature = "calendar-ext")]
314 (Self::GDayLiteral(l), Self::GDayLiteral(r)) => l == r,
315 #[cfg(feature = "sep-0002")]
316 (Self::DurationLiteral(l), Self::DurationLiteral(r)) => l == r,
317 #[cfg(feature = "sep-0002")]
318 (Self::YearMonthDurationLiteral(l), Self::YearMonthDurationLiteral(r)) => l == r,
319 #[cfg(feature = "sep-0002")]
320 (Self::DayTimeDurationLiteral(l), Self::DayTimeDurationLiteral(r)) => l == r,
321 (
322 Self::OtherTypedLiteral {
323 value: lv,
324 datatype: ld,
325 },
326 Self::OtherTypedLiteral {
327 value: rv,
328 datatype: rd,
329 },
330 ) => lv == rv && ld == rd,
331 #[cfg(feature = "rdf-star")]
332 (Self::Triple(l), Self::Triple(r)) => l == r,
333 (_, _) => unreachable!(),
334 }
335 }
336}
337
338impl Eq for ExpressionTerm {}
339
340impl Hash for ExpressionTerm {
341 #[inline]
342 fn hash<H: Hasher>(&self, state: &mut H) {
343 discriminant(self).hash(state);
344 match self {
345 ExpressionTerm::NamedNode(v) => v.hash(state),
346 ExpressionTerm::BlankNode(v) => v.hash(state),
347 ExpressionTerm::StringLiteral(v) => v.hash(state),
348 ExpressionTerm::LangStringLiteral { value, language } => (value, language).hash(state),
349 ExpressionTerm::BooleanLiteral(v) => v.hash(state),
350 ExpressionTerm::IntegerLiteral(v) => v.hash(state),
351 ExpressionTerm::DecimalLiteral(v) => v.hash(state),
352 ExpressionTerm::FloatLiteral(v) => v.to_be_bytes().hash(state),
353 ExpressionTerm::DoubleLiteral(v) => v.to_be_bytes().hash(state),
354 ExpressionTerm::DateTimeLiteral(v) => v.hash(state),
355 #[cfg(feature = "sep-0002")]
356 ExpressionTerm::DateLiteral(v) => v.hash(state),
357 #[cfg(feature = "sep-0002")]
358 ExpressionTerm::TimeLiteral(v) => v.hash(state),
359 #[cfg(feature = "calendar-ext")]
360 ExpressionTerm::GYearLiteral(v) => v.hash(state),
361 #[cfg(feature = "calendar-ext")]
362 ExpressionTerm::GYearMonthLiteral(v) => v.hash(state),
363 #[cfg(feature = "calendar-ext")]
364 ExpressionTerm::GMonthLiteral(v) => v.hash(state),
365 #[cfg(feature = "calendar-ext")]
366 ExpressionTerm::GMonthDayLiteral(v) => v.hash(state),
367 #[cfg(feature = "calendar-ext")]
368 ExpressionTerm::GDayLiteral(v) => v.hash(state),
369 #[cfg(feature = "sep-0002")]
370 ExpressionTerm::DurationLiteral(v) => v.hash(state),
371 #[cfg(feature = "sep-0002")]
372 ExpressionTerm::YearMonthDurationLiteral(v) => v.hash(state),
373 #[cfg(feature = "sep-0002")]
374 ExpressionTerm::DayTimeDurationLiteral(v) => v.hash(state),
375 ExpressionTerm::OtherTypedLiteral { value, datatype } => (value, datatype).hash(state),
376 #[cfg(feature = "rdf-star")]
377 ExpressionTerm::Triple(v) => v.hash(state),
378 }
379 }
380}
381
382impl From<Term> for ExpressionTerm {
383 #[inline]
384 fn from(term: Term) -> Self {
385 match term {
386 Term::NamedNode(t) => Self::NamedNode(t),
387 Term::BlankNode(t) => Self::BlankNode(t),
388 Term::Literal(t) => {
389 let (value, datatype, language) = t.destruct();
390 if let Some(language) = language {
391 Self::LangStringLiteral { value, language }
392 } else if let Some(datatype) = datatype {
393 parse_typed_literal(&value, datatype.as_str())
394 .unwrap_or(Self::OtherTypedLiteral { value, datatype })
395 } else {
396 Self::StringLiteral(value)
397 }
398 }
399 #[cfg(feature = "rdf-star")]
400 Term::Triple(t) => Self::Triple(Box::new((*t).into())),
401 }
402 }
403}
404
405impl From<ExpressionTerm> for Term {
406 #[inline]
407 fn from(term: ExpressionTerm) -> Self {
408 match term {
409 ExpressionTerm::NamedNode(t) => t.into(),
410 ExpressionTerm::BlankNode(t) => t.into(),
411 ExpressionTerm::StringLiteral(value) => Literal::from(value).into(),
412 ExpressionTerm::LangStringLiteral { value, language } => {
413 Literal::new_language_tagged_literal_unchecked(value, language).into()
414 }
415 ExpressionTerm::BooleanLiteral(value) => Literal::from(value).into(),
416 ExpressionTerm::IntegerLiteral(value) => Literal::from(value).into(),
417 ExpressionTerm::DecimalLiteral(value) => Literal::from(value).into(),
418 ExpressionTerm::FloatLiteral(value) => Literal::from(value).into(),
419 ExpressionTerm::DoubleLiteral(value) => Literal::from(value).into(),
420 ExpressionTerm::DateTimeLiteral(value) => Literal::from(value).into(),
421 #[cfg(feature = "sep-0002")]
422 ExpressionTerm::DateLiteral(value) => Literal::from(value).into(),
423 #[cfg(feature = "sep-0002")]
424 ExpressionTerm::TimeLiteral(value) => Literal::from(value).into(),
425 #[cfg(feature = "calendar-ext")]
426 ExpressionTerm::GYearLiteral(value) => Literal::from(value).into(),
427 #[cfg(feature = "calendar-ext")]
428 ExpressionTerm::GYearMonthLiteral(value) => Literal::from(value).into(),
429 #[cfg(feature = "calendar-ext")]
430 ExpressionTerm::GMonthLiteral(value) => Literal::from(value).into(),
431 #[cfg(feature = "calendar-ext")]
432 ExpressionTerm::GMonthDayLiteral(value) => Literal::from(value).into(),
433 #[cfg(feature = "calendar-ext")]
434 ExpressionTerm::GDayLiteral(value) => Literal::from(value).into(),
435 #[cfg(feature = "sep-0002")]
436 ExpressionTerm::DurationLiteral(value) => Literal::from(value).into(),
437 #[cfg(feature = "sep-0002")]
438 ExpressionTerm::YearMonthDurationLiteral(value) => Literal::from(value).into(),
439 #[cfg(feature = "sep-0002")]
440 ExpressionTerm::DayTimeDurationLiteral(value) => Literal::from(value).into(),
441 ExpressionTerm::OtherTypedLiteral { value, datatype } => {
442 Literal::new_typed_literal(value, datatype).into()
443 }
444 #[cfg(feature = "rdf-star")]
445 ExpressionTerm::Triple(t) => Triple::from(*t).into(),
446 }
447 }
448}
449
450impl From<NamedNode> for ExpressionTerm {
451 #[inline]
452 fn from(term: NamedNode) -> Self {
453 Self::NamedNode(term)
454 }
455}
456impl From<bool> for ExpressionTerm {
457 fn from(value: bool) -> Self {
458 Self::BooleanLiteral(value.into())
459 }
460}
461
462impl ExpressionTerm {
463 pub(crate) fn effective_boolean_value(&self) -> Option<bool> {
465 match self {
466 ExpressionTerm::BooleanLiteral(value) => Some((*value).into()),
467 ExpressionTerm::StringLiteral(value) => Some(!value.is_empty()),
468 ExpressionTerm::FloatLiteral(value) => Some(Boolean::from(*value).into()),
469 ExpressionTerm::DoubleLiteral(value) => Some(Boolean::from(*value).into()),
470 ExpressionTerm::IntegerLiteral(value) => Some(Boolean::from(*value).into()),
471 ExpressionTerm::DecimalLiteral(value) => Some(Boolean::from(*value).into()),
472 _ => None,
473 }
474 }
475}
476
477fn parse_typed_literal(value: &str, datatype: &str) -> Option<ExpressionTerm> {
478 Some(match datatype {
479 "http://www.w3.org/2001/XMLSchema#boolean" => {
480 ExpressionTerm::BooleanLiteral(value.parse().ok()?)
481 }
482 "http://www.w3.org/2001/XMLSchema#string" => ExpressionTerm::StringLiteral(value.into()),
483 "http://www.w3.org/2001/XMLSchema#float" => {
484 ExpressionTerm::FloatLiteral(value.parse().ok()?)
485 }
486 "http://www.w3.org/2001/XMLSchema#double" => {
487 ExpressionTerm::DoubleLiteral(value.parse().ok()?)
488 }
489 "http://www.w3.org/2001/XMLSchema#decimal" => {
490 ExpressionTerm::DecimalLiteral(value.parse().ok()?)
491 }
492 "http://www.w3.org/2001/XMLSchema#integer"
493 | "http://www.w3.org/2001/XMLSchema#byte"
494 | "http://www.w3.org/2001/XMLSchema#short"
495 | "http://www.w3.org/2001/XMLSchema#int"
496 | "http://www.w3.org/2001/XMLSchema#long"
497 | "http://www.w3.org/2001/XMLSchema#unsignedByte"
498 | "http://www.w3.org/2001/XMLSchema#unsignedShort"
499 | "http://www.w3.org/2001/XMLSchema#unsignedInt"
500 | "http://www.w3.org/2001/XMLSchema#unsignedLong"
501 | "http://www.w3.org/2001/XMLSchema#positiveInteger"
502 | "http://www.w3.org/2001/XMLSchema#negativeInteger"
503 | "http://www.w3.org/2001/XMLSchema#nonPositiveInteger"
504 | "http://www.w3.org/2001/XMLSchema#nonNegativeInteger" => {
505 ExpressionTerm::IntegerLiteral(value.parse().ok()?)
506 }
507 "http://www.w3.org/2001/XMLSchema#dateTime"
508 | "http://www.w3.org/2001/XMLSchema#dateTimeStamp" => {
509 ExpressionTerm::DateTimeLiteral(value.parse().ok()?)
510 }
511 #[cfg(feature = "sep-0002")]
512 "http://www.w3.org/2001/XMLSchema#time" => ExpressionTerm::TimeLiteral(value.parse().ok()?),
513 #[cfg(feature = "sep-0002")]
514 "http://www.w3.org/2001/XMLSchema#date" => ExpressionTerm::DateLiteral(value.parse().ok()?),
515 #[cfg(feature = "calendar-ext")]
516 "http://www.w3.org/2001/XMLSchema#gYearMonth" => {
517 ExpressionTerm::GYearMonthLiteral(value.parse().ok()?)
518 }
519 #[cfg(feature = "calendar-ext")]
520 "http://www.w3.org/2001/XMLSchema#gYear" => {
521 ExpressionTerm::GYearLiteral(value.parse().ok()?)
522 }
523 #[cfg(feature = "calendar-ext")]
524 "http://www.w3.org/2001/XMLSchema#gMonthDay" => {
525 ExpressionTerm::GMonthDayLiteral(value.parse().ok()?)
526 }
527 #[cfg(feature = "calendar-ext")]
528 "http://www.w3.org/2001/XMLSchema#gDay" => ExpressionTerm::GDayLiteral(value.parse().ok()?),
529 #[cfg(feature = "calendar-ext")]
530 "http://www.w3.org/2001/XMLSchema#gMonth" => {
531 ExpressionTerm::GMonthLiteral(value.parse().ok()?)
532 }
533 #[cfg(feature = "sep-0002")]
534 "http://www.w3.org/2001/XMLSchema#duration" => {
535 ExpressionTerm::DurationLiteral(value.parse().ok()?)
536 }
537 #[cfg(feature = "sep-0002")]
538 "http://www.w3.org/2001/XMLSchema#yearMonthDuration" => {
539 ExpressionTerm::YearMonthDurationLiteral(value.parse().ok()?)
540 }
541 #[cfg(feature = "sep-0002")]
542 "http://www.w3.org/2001/XMLSchema#dayTimeDuration" => {
543 ExpressionTerm::DayTimeDurationLiteral(value.parse().ok()?)
544 }
545 _ => return None,
546 })
547}
548
549#[cfg(feature = "rdf-star")]
550#[derive(Clone, PartialEq, Eq, Hash)]
551pub struct ExpressionTriple {
552 pub subject: ExpressionSubject,
553 pub predicate: NamedNode,
554 pub object: ExpressionTerm,
555}
556
557#[cfg(feature = "rdf-star")]
558impl From<ExpressionTriple> for ExpressionTerm {
559 #[inline]
560 fn from(triple: ExpressionTriple) -> Self {
561 Self::Triple(Box::new(triple))
562 }
563}
564
565#[cfg(feature = "rdf-star")]
566impl From<Triple> for ExpressionTriple {
567 #[inline]
568 fn from(triple: Triple) -> Self {
569 ExpressionTriple {
570 subject: triple.subject.into(),
571 predicate: triple.predicate,
572 object: triple.object.into(),
573 }
574 }
575}
576
577#[cfg(feature = "rdf-star")]
578impl From<ExpressionTriple> for Triple {
579 #[inline]
580 fn from(triple: ExpressionTriple) -> Self {
581 Triple {
582 subject: triple.subject.into(),
583 predicate: triple.predicate,
584 object: triple.object.into(),
585 }
586 }
587}
588
589#[cfg(feature = "rdf-star")]
590impl ExpressionTriple {
591 pub fn new(
592 subject: ExpressionTerm,
593 predicate: ExpressionTerm,
594 object: ExpressionTerm,
595 ) -> Option<Self> {
596 if !matches!(
597 subject,
598 ExpressionTerm::NamedNode(_) | ExpressionTerm::BlankNode(_) | ExpressionTerm::Triple(_)
599 ) {
600 return None;
601 }
602 if !matches!(predicate, ExpressionTerm::NamedNode(_)) {
603 return None;
604 }
605 Some(Self {
606 subject: match subject {
607 ExpressionTerm::NamedNode(s) => ExpressionSubject::NamedNode(s),
608 ExpressionTerm::BlankNode(s) => ExpressionSubject::BlankNode(s),
609 ExpressionTerm::Triple(s) => ExpressionSubject::Triple(s),
610 _ => return None,
611 },
612 predicate: if let ExpressionTerm::NamedNode(p) = predicate {
613 p
614 } else {
615 return None;
616 },
617 object,
618 })
619 }
620}
621
622#[cfg(feature = "rdf-star")]
623#[derive(Clone, PartialEq, Eq, Hash)]
624pub enum ExpressionSubject {
625 NamedNode(NamedNode),
626 BlankNode(BlankNode),
627 Triple(Box<ExpressionTriple>),
628}
629
630#[cfg(feature = "rdf-star")]
631impl From<ExpressionSubject> for ExpressionTerm {
632 #[inline]
633 fn from(subject: ExpressionSubject) -> Self {
634 match subject {
635 ExpressionSubject::NamedNode(s) => Self::NamedNode(s),
636 ExpressionSubject::BlankNode(s) => Self::BlankNode(s),
637 ExpressionSubject::Triple(s) => Self::Triple(s),
638 }
639 }
640}
641
642#[cfg(feature = "rdf-star")]
643impl From<ExpressionSubject> for Subject {
644 #[inline]
645 fn from(subject: ExpressionSubject) -> Self {
646 match subject {
647 ExpressionSubject::NamedNode(s) => s.into(),
648 ExpressionSubject::BlankNode(s) => s.into(),
649 ExpressionSubject::Triple(s) => Triple::from(*s).into(),
650 }
651 }
652}
653
654#[cfg(feature = "rdf-star")]
655impl From<Subject> for ExpressionSubject {
656 #[inline]
657 fn from(subject: Subject) -> Self {
658 match subject {
659 Subject::NamedNode(s) => Self::NamedNode(s),
660 Subject::BlankNode(s) => Self::BlankNode(s),
661 Subject::Triple(s) => ExpressionSubject::Triple(Box::new(ExpressionTriple::from(*s))),
662 }
663 }
664}