Skip to main content

rdf_syntax/term/
ref.rs

1use core::fmt;
2use std::borrow::Cow;
3use std::cmp::Ordering;
4
5use into_owned_trait::IntoOwned;
6use iref::Iri;
7
8use crate::{BlankId, IdRef, LiteralRef, RdfDisplay};
9
10use super::{CowTerm, GroundTermRef, Term};
11
12/// Term reference.
13#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub enum TermRef<'a> {
15	/// Blank identifier.
16	BlankId(&'a BlankId),
17
18	/// Ground term.
19	Ground(GroundTermRef<'a>),
20}
21
22impl<'a> TermRef<'a> {
23	/// Checks if this term is an identifier, i.e. a blank node identifier or
24	/// an IRI (as opposed to a literal).
25	pub fn is_id(&self) -> bool {
26		matches!(self, Self::BlankId(_) | Self::Ground(GroundTermRef::Iri(_)))
27	}
28
29	/// Returns this term as an identifier, unless it is a literal.
30	pub fn as_id(&self) -> Option<IdRef<'a>> {
31		match self {
32			Self::BlankId(b) => Some(IdRef::BlankId(b)),
33			Self::Ground(GroundTermRef::Iri(iri)) => Some(IdRef::Iri(iri)),
34			_ => None,
35		}
36	}
37
38	/// Turns this term into an identifier, or returns the literal value if it
39	/// isn't one.
40	pub fn into_id(self) -> Result<IdRef<'a>, LiteralRef<'a>> {
41		match self {
42			Self::BlankId(b) => Ok(IdRef::BlankId(b)),
43			Self::Ground(GroundTermRef::Iri(iri)) => Ok(IdRef::Iri(iri)),
44			Self::Ground(GroundTermRef::Literal(lit)) => Err(lit),
45		}
46	}
47
48	/// Checks if this is a blank node identifier.
49	pub fn is_blank_id(&self) -> bool {
50		matches!(self, Self::BlankId(_))
51	}
52
53	/// Checks if this is a ground term (an IRI or a literal, but not a blank
54	/// node identifier).
55	pub fn is_ground(&self) -> bool {
56		matches!(self, Self::Ground(_))
57	}
58
59	/// Checks if this is an IRI.
60	pub fn is_iri(&self) -> bool {
61		matches!(self, Self::Ground(GroundTermRef::Iri(_)))
62	}
63
64	/// Checks if this is a literal.
65	pub fn is_literal(&self) -> bool {
66		matches!(self, Self::Ground(GroundTermRef::Literal(_)))
67	}
68
69	/// Returns this term as a blank node identifier, if it is one.
70	pub fn as_blank_id(&self) -> Option<&'a BlankId> {
71		match self {
72			Self::BlankId(b) => Some(b),
73			_ => None,
74		}
75	}
76
77	/// Returns this term as a ground term, if it is one.
78	pub fn as_ground(&self) -> Option<GroundTermRef<'a>> {
79		match self {
80			Self::Ground(g) => Some(*g),
81			_ => None,
82		}
83	}
84
85	/// Returns this term as an IRI, if it is one.
86	pub fn as_iri(&self) -> Option<&'a Iri> {
87		match self {
88			Self::Ground(g) => g.as_iri(),
89			_ => None,
90		}
91	}
92
93	/// Returns this term as a literal, if it is one.
94	pub fn as_literal(&self) -> Option<LiteralRef<'a>> {
95		match self {
96			Self::Ground(g) => g.as_literal(),
97			_ => None,
98		}
99	}
100
101	/// Turns this term into a ground term, or returns the blank node
102	/// identifier if it isn't one.
103	pub fn into_ground(self) -> Result<GroundTermRef<'a>, &'a BlankId> {
104		match self {
105			Self::Ground(g) => Ok(g),
106			Self::BlankId(b) => Err(b),
107		}
108	}
109
110	/// Turns this term reference into a copy-on-write term.
111	pub fn into_cow(self) -> CowTerm<'a> {
112		match self {
113			Self::BlankId(b) => CowTerm::BlankId(Cow::Borrowed(b)),
114			Self::Ground(g) => CowTerm::Ground(g.into_cow()),
115		}
116	}
117}
118
119impl TermRef<'_> {
120	/// Clones the referenced term.
121	pub fn to_owned(&self) -> Term {
122		(*self).into_owned()
123	}
124}
125
126impl IntoOwned for TermRef<'_> {
127	type Owned = Term;
128
129	fn into_owned(self) -> Term {
130		match self {
131			Self::BlankId(blank_id) => Term::BlankId(blank_id.to_owned()),
132			Self::Ground(named) => Term::Ground(named.to_owned()),
133		}
134	}
135}
136
137impl equivalent::Equivalent<Term> for TermRef<'_> {
138	fn equivalent(&self, key: &Term) -> bool {
139		self == key
140	}
141}
142
143impl equivalent::Comparable<Term> for TermRef<'_> {
144	fn compare(&self, key: &Term) -> std::cmp::Ordering {
145		self.partial_cmp(key).unwrap()
146	}
147}
148
149impl From<TermRef<'_>> for Term {
150	fn from(value: TermRef<'_>) -> Self {
151		value.to_owned()
152	}
153}
154
155impl PartialEq<Term> for TermRef<'_> {
156	fn eq(&self, other: &Term) -> bool {
157		match (self, other) {
158			(Self::BlankId(a), Term::BlankId(b)) => *a == b,
159			(Self::Ground(a), Term::Ground(b)) => a == b,
160			_ => false,
161		}
162	}
163}
164
165impl PartialOrd<Term> for TermRef<'_> {
166	fn partial_cmp(&self, other: &Term) -> Option<Ordering> {
167		match (self, other) {
168			(Self::BlankId(a), Term::BlankId(b)) => (*a).partial_cmp(b),
169			(Self::BlankId(_), Term::Ground(_)) => Some(Ordering::Less),
170			(Self::Ground(_), Term::BlankId(_)) => Some(Ordering::Greater),
171			(Self::Ground(a), Term::Ground(b)) => (*a).partial_cmp(b),
172		}
173	}
174}
175
176impl fmt::Display for TermRef<'_> {
177	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
178		match self {
179			Self::BlankId(id) => id.fmt(f),
180			Self::Ground(g) => g.fmt(f),
181		}
182	}
183}
184
185impl RdfDisplay for TermRef<'_> {
186	fn rdf_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
187		match self {
188			Self::BlankId(id) => id.rdf_fmt(f),
189			Self::Ground(g) => g.rdf_fmt(f),
190		}
191	}
192}