Skip to main content

rdf_syntax/term/
cow.rs

1use core::fmt;
2use std::borrow::Cow;
3use std::cmp::Ordering;
4
5use into_owned_trait::IntoOwned;
6use iref::{Iri, IriBuf};
7
8use crate::{
9	BlankId, BlankIdBuf, CowId, CowLiteral, GroundTerm, Id, IdRef, Literal, LiteralRef, RdfDisplay,
10	TermRef,
11};
12
13use super::{CowGroundTerm, Term};
14
15/// Copy-on-write term.
16#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub enum CowTerm<'a> {
18	/// Blank node identifier.
19	BlankId(Cow<'a, BlankId>),
20
21	/// Ground term.
22	Ground(CowGroundTerm<'a>),
23}
24
25impl CowTerm<'_> {
26	/// Checks if this term is an identifier, i.e. a blank node identifier or
27	/// an IRI (as opposed to a literal).
28	pub fn is_id(&self) -> bool {
29		matches!(self, Self::BlankId(_) | Self::Ground(CowGroundTerm::Iri(_)))
30	}
31
32	/// Returns this term as an identifier, unless it is a literal.
33	pub fn as_id(&self) -> Option<IdRef<'_>> {
34		match self {
35			Self::BlankId(b) => Some(IdRef::BlankId(b)),
36			Self::Ground(CowGroundTerm::Iri(iri)) => Some(IdRef::Iri(iri)),
37			_ => None,
38		}
39	}
40
41	/// Checks if this is a blank node identifier.
42	pub fn is_blank_id(&self) -> bool {
43		matches!(self, Self::BlankId(_))
44	}
45
46	/// Checks if this is a ground term (an IRI or a literal, but not a blank
47	/// node identifier).
48	pub fn is_ground(&self) -> bool {
49		matches!(self, Self::Ground(_))
50	}
51
52	/// Checks if this is an IRI.
53	pub fn is_iri(&self) -> bool {
54		matches!(self, Self::Ground(CowGroundTerm::Iri(_)))
55	}
56
57	/// Checks if this is a literal.
58	pub fn is_literal(&self) -> bool {
59		matches!(self, Self::Ground(CowGroundTerm::Literal(_)))
60	}
61
62	/// Returns this term as a blank node identifier, if it is one.
63	pub fn as_blank_id(&self) -> Option<&BlankId> {
64		match self {
65			Self::BlankId(b) => Some(b),
66			_ => None,
67		}
68	}
69
70	/// Returns this term as an IRI, if it is one.
71	pub fn as_iri(&self) -> Option<&Iri> {
72		match self {
73			Self::Ground(g) => g.as_iri(),
74			_ => None,
75		}
76	}
77
78	/// Returns this term as a ground term, if it is one.
79	pub fn as_ground(&self) -> Option<&CowGroundTerm<'_>> {
80		match self {
81			Self::Ground(g) => Some(g),
82			_ => None,
83		}
84	}
85
86	/// Returns this term as a literal, if it is one.
87	pub fn as_literal(&self) -> Option<LiteralRef<'_>> {
88		match self {
89			Self::Ground(g) => g.as_literal(),
90			_ => None,
91		}
92	}
93
94	/// Returns a reference to this term.
95	pub fn as_ref(&self) -> TermRef<'_> {
96		match self {
97			Self::BlankId(b) => TermRef::BlankId(b),
98			Self::Ground(g) => TermRef::Ground(g.as_ref()),
99		}
100	}
101
102	/// Clones the term, if needed, to get rid of the borrow.
103	pub fn into_owned(self) -> Term {
104		match self {
105			Self::BlankId(b) => Term::BlankId(b.into_owned()),
106			Self::Ground(t) => Term::Ground(t.into_owned()),
107		}
108	}
109}
110
111impl<'a> CowTerm<'a> {
112	/// Turns this term into a ground term, or returns the blank node
113	/// identifier if it isn't one.
114	pub fn into_ground(self) -> Result<CowGroundTerm<'a>, Cow<'a, BlankId>> {
115		match self {
116			Self::Ground(g) => Ok(g),
117			Self::BlankId(b) => Err(b),
118		}
119	}
120
121	/// Turns this term into an identifier, or returns the literal value if it
122	/// isn't one.
123	pub fn into_id(self) -> Result<CowId<'a>, CowLiteral<'a>> {
124		match self {
125			Self::BlankId(b) => Ok(CowId::BlankId(b)),
126			Self::Ground(CowGroundTerm::Iri(iri)) => Ok(CowId::Iri(iri)),
127			Self::Ground(CowGroundTerm::Literal(lit)) => Err(lit),
128		}
129	}
130}
131
132impl<'a> From<TermRef<'a>> for CowTerm<'a> {
133	fn from(value: TermRef<'a>) -> Self {
134		value.into_cow()
135	}
136}
137
138impl From<CowTerm<'_>> for Term {
139	fn from(value: CowTerm<'_>) -> Self {
140		value.into_owned()
141	}
142}
143
144impl IntoOwned for CowTerm<'_> {
145	type Owned = Term;
146
147	fn into_owned(self) -> Term {
148		match self {
149			Self::BlankId(b) => Term::BlankId(b.into_owned()),
150			Self::Ground(t) => Term::Ground(t.into_owned()),
151		}
152	}
153}
154
155impl equivalent::Equivalent<Term> for CowTerm<'_> {
156	fn equivalent(&self, key: &Term) -> bool {
157		self == key
158	}
159}
160
161impl equivalent::Comparable<Term> for CowTerm<'_> {
162	fn compare(&self, key: &Term) -> std::cmp::Ordering {
163		self.partial_cmp(key).unwrap()
164	}
165}
166
167impl From<GroundTerm> for CowTerm<'_> {
168	fn from(value: GroundTerm) -> Self {
169		Self::Ground(value.into())
170	}
171}
172
173impl From<Term> for CowTerm<'_> {
174	fn from(value: Term) -> Self {
175		value.into_cow()
176	}
177}
178
179impl<'a> From<&'a Term> for CowTerm<'a> {
180	fn from(value: &'a Term) -> Self {
181		value.as_cow()
182	}
183}
184
185impl<'a> From<&'a Literal> for CowTerm<'a> {
186	fn from(value: &'a Literal) -> Self {
187		Self::Ground(value.into())
188	}
189}
190
191impl<'a> From<CowLiteral<'a>> for CowTerm<'a> {
192	fn from(value: CowLiteral<'a>) -> Self {
193		Self::Ground(value.into())
194	}
195}
196
197impl<'a> From<LiteralRef<'a>> for CowTerm<'a> {
198	fn from(value: LiteralRef<'a>) -> Self {
199		Self::Ground(value.into())
200	}
201}
202
203impl<'a> From<&'a Id> for CowTerm<'a> {
204	fn from(value: &'a Id) -> Self {
205		match value {
206			Id::BlankId(b) => b.into(),
207			Id::Iri(i) => i.into(),
208		}
209	}
210}
211
212impl<'a> From<&'a BlankId> for CowTerm<'a> {
213	fn from(value: &'a BlankId) -> Self {
214		Self::BlankId(Cow::Borrowed(value))
215	}
216}
217
218impl<'a> From<&'a BlankIdBuf> for CowTerm<'a> {
219	fn from(value: &'a BlankIdBuf) -> Self {
220		Self::BlankId(Cow::Borrowed(value))
221	}
222}
223
224impl<'a> From<&'a Iri> for CowTerm<'a> {
225	fn from(value: &'a Iri) -> Self {
226		Self::Ground(value.into())
227	}
228}
229
230impl<'a> From<&'a IriBuf> for CowTerm<'a> {
231	fn from(value: &'a IriBuf) -> Self {
232		Self::Ground(value.into())
233	}
234}
235
236impl<'a> From<&'a str> for CowTerm<'a> {
237	fn from(value: &'a str) -> Self {
238		Self::Ground(value.into())
239	}
240}
241
242impl<'a> From<&'a String> for CowTerm<'a> {
243	fn from(value: &'a String) -> Self {
244		Self::Ground(value.into())
245	}
246}
247
248impl PartialEq<Iri> for CowTerm<'_> {
249	fn eq(&self, other: &Iri) -> bool {
250		match self {
251			Self::Ground(CowGroundTerm::Iri(this)) => this.as_ref() == other,
252			_ => false,
253		}
254	}
255}
256
257impl PartialEq<&Iri> for CowTerm<'_> {
258	fn eq(&self, other: &&Iri) -> bool {
259		self.eq(*other)
260	}
261}
262
263impl PartialEq<Term> for CowTerm<'_> {
264	fn eq(&self, other: &Term) -> bool {
265		self.as_ref() == *other
266	}
267}
268
269impl PartialEq<CowTerm<'_>> for Term {
270	fn eq(&self, other: &CowTerm<'_>) -> bool {
271		*self == other.as_ref()
272	}
273}
274
275impl<'a> PartialEq<TermRef<'a>> for CowTerm<'_> {
276	fn eq(&self, other: &TermRef<'a>) -> bool {
277		self.as_ref() == *other
278	}
279}
280
281impl PartialEq<CowTerm<'_>> for TermRef<'_> {
282	fn eq(&self, other: &CowTerm<'_>) -> bool {
283		*self == other.as_ref()
284	}
285}
286
287impl PartialOrd<Term> for CowTerm<'_> {
288	fn partial_cmp(&self, other: &Term) -> Option<Ordering> {
289		self.as_ref().partial_cmp(other)
290	}
291}
292
293impl PartialOrd<CowTerm<'_>> for Term {
294	fn partial_cmp(&self, other: &CowTerm<'_>) -> Option<Ordering> {
295		self.partial_cmp(&other.as_ref())
296	}
297}
298
299impl<'a> PartialOrd<TermRef<'a>> for CowTerm<'_> {
300	fn partial_cmp(&self, other: &TermRef<'a>) -> Option<Ordering> {
301		self.as_ref().partial_cmp(other)
302	}
303}
304
305impl PartialOrd<CowTerm<'_>> for TermRef<'_> {
306	fn partial_cmp(&self, other: &CowTerm<'_>) -> Option<Ordering> {
307		self.partial_cmp(&other.as_ref())
308	}
309}
310
311impl fmt::Display for CowTerm<'_> {
312	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
313		match self {
314			Self::BlankId(id) => id.fmt(f),
315			Self::Ground(g) => g.fmt(f),
316		}
317	}
318}
319
320impl RdfDisplay for CowTerm<'_> {
321	fn rdf_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
322		match self {
323			Self::BlankId(id) => id.rdf_fmt(f),
324			Self::Ground(g) => g.rdf_fmt(f),
325		}
326	}
327}