1use std::borrow::Cow;
2use std::cmp::Ordering;
3use std::fmt;
4use std::hash::Hash;
5
6use iref::{Iri, IriBuf};
7use rdf_types::pattern::{AsPattern, Pattern};
8
9use crate::{BlankId, BlankIdBuf, Id, IdRef, Literal, LiteralRef, RdfDisplay};
10
11mod cow;
12pub mod generator;
13mod ground;
14mod r#ref;
15
16pub use cow::*;
17pub use generator::Generator;
18pub use ground::*;
19pub use r#ref::*;
20
21#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26#[cfg_attr(feature = "serde", serde(untagged))]
27pub enum Term {
28 BlankId(BlankIdBuf),
30
31 Ground(GroundTerm),
33}
34
35impl Term {
36 pub fn iri(iri: IriBuf) -> Self {
38 Self::Ground(GroundTerm::Iri(iri))
39 }
40
41 pub fn literal(literal: Literal) -> Self {
43 Self::Ground(GroundTerm::Literal(literal))
44 }
45
46 pub fn id(id: Id) -> Self {
48 match id {
49 Id::Iri(iri) => Self::iri(iri),
50 Id::BlankId(b) => Self::BlankId(b),
51 }
52 }
53
54 pub fn is_id(&self) -> bool {
57 matches!(self, Self::BlankId(_) | Self::Ground(GroundTerm::Iri(_)))
58 }
59
60 pub fn as_id(&self) -> Option<IdRef<'_>> {
62 match self {
63 Self::BlankId(b) => Some(IdRef::BlankId(b)),
64 Self::Ground(GroundTerm::Iri(iri)) => Some(IdRef::Iri(iri)),
65 _ => None,
66 }
67 }
68
69 pub fn is_blank_id(&self) -> bool {
71 matches!(self, Self::BlankId(_))
72 }
73
74 pub fn is_ground(&self) -> bool {
77 matches!(self, Self::Ground(_))
78 }
79
80 pub fn as_blank_id(&self) -> Option<&BlankId> {
82 match self {
83 Self::BlankId(b) => Some(b),
84 Self::Ground(_) => None,
85 }
86 }
87
88 pub fn as_ground(&self) -> Option<&GroundTerm> {
90 match self {
91 Self::Ground(g) => Some(g),
92 _ => None,
93 }
94 }
95
96 pub fn into_ground(self) -> Result<GroundTerm, BlankIdBuf> {
99 match self {
100 Self::Ground(g) => Ok(g),
101 Self::BlankId(b) => Err(b),
102 }
103 }
104
105 pub fn is_iri(&self) -> bool {
107 matches!(self, Self::Ground(GroundTerm::Iri(_)))
108 }
109
110 pub fn as_iri(&self) -> Option<&Iri> {
112 match self {
113 Self::Ground(t) => t.as_iri(),
114 Self::BlankId(_) => None,
115 }
116 }
117
118 pub fn into_iri(self) -> Result<IriBuf, Self> {
120 match self {
121 Self::Ground(GroundTerm::Iri(iri)) => Ok(iri),
122 other => Err(other),
123 }
124 }
125
126 pub fn is_literal(&self) -> bool {
128 matches!(self, Self::Ground(GroundTerm::Literal(_)))
129 }
130
131 pub fn as_literal(&self) -> Option<LiteralRef<'_>> {
133 match self {
134 Self::Ground(t) => t.as_literal(),
135 Self::BlankId(_) => None,
136 }
137 }
138
139 pub fn as_ref(&self) -> TermRef<'_> {
141 match self {
142 Self::BlankId(blank_id) => TermRef::BlankId(blank_id),
143 Self::Ground(named) => TermRef::Ground(named.as_ref()),
144 }
145 }
146
147 pub fn as_cow(&self) -> CowTerm<'_> {
149 match self {
150 Self::BlankId(blank_id) => CowTerm::BlankId(Cow::Borrowed(blank_id)),
151 Self::Ground(named) => CowTerm::Ground(named.as_cow()),
152 }
153 }
154
155 pub fn into_cow(self) -> CowTerm<'static> {
157 match self {
158 Self::BlankId(blank_id) => CowTerm::BlankId(Cow::Owned(blank_id)),
159 Self::Ground(named) => CowTerm::Ground(named.into_cow()),
160 }
161 }
162
163 pub fn into_id(self) -> Result<Id, Literal> {
166 match self {
167 Self::BlankId(blank) => Ok(Id::BlankId(blank)),
168 Self::Ground(GroundTerm::Iri(iri)) => Ok(Id::Iri(iri)),
169 Self::Ground(GroundTerm::Literal(lit)) => Err(lit),
170 }
171 }
172}
173
174impl From<IriBuf> for Term {
175 fn from(value: IriBuf) -> Self {
176 Self::iri(value)
177 }
178}
179
180impl From<Literal> for Term {
181 fn from(value: Literal) -> Self {
182 Self::literal(value)
183 }
184}
185
186impl From<Id> for Term {
187 fn from(value: Id) -> Self {
188 match value {
189 Id::BlankId(b) => Self::BlankId(b),
190 Id::Iri(i) => Self::Ground(GroundTerm::Iri(i)),
191 }
192 }
193}
194
195impl From<GroundTerm> for Term {
196 fn from(value: GroundTerm) -> Self {
197 Self::Ground(value)
198 }
199}
200
201impl From<BlankIdBuf> for Term {
202 fn from(value: BlankIdBuf) -> Self {
203 Self::BlankId(value)
204 }
205}
206
207impl Hash for Term {
208 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
209 match self {
210 Self::BlankId(id) => id.hash(state),
211 Self::Ground(l) => l.hash(state),
212 }
213 }
214}
215
216impl fmt::Display for Term {
217 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
218 match self {
219 Self::BlankId(id) => id.fmt(f),
220 Self::Ground(lit) => lit.fmt(f),
221 }
222 }
223}
224
225impl RdfDisplay for Term {
226 fn rdf_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
227 match self {
228 Self::BlankId(id) => id.rdf_fmt(f),
229 Self::Ground(lit) => lit.rdf_fmt(f),
230 }
231 }
232}
233
234impl<'a> PartialEq<TermRef<'a>> for Term {
235 fn eq(&self, other: &TermRef<'a>) -> bool {
236 match (self, other) {
237 (Self::BlankId(a), TermRef::BlankId(b)) => a == *b,
238 (Self::Ground(a), TermRef::Ground(b)) => a == b,
239 _ => false,
240 }
241 }
242}
243
244impl<'a> PartialOrd<TermRef<'a>> for Term {
245 fn partial_cmp(&self, other: &TermRef<'a>) -> Option<Ordering> {
246 match (self, other) {
247 (Self::BlankId(a), TermRef::BlankId(b)) => a.as_blank_id().partial_cmp(*b),
248 (Self::BlankId(_), TermRef::Ground(_)) => Some(Ordering::Less),
249 (Self::Ground(_), TermRef::BlankId(_)) => Some(Ordering::Greater),
250 (Self::Ground(a), TermRef::Ground(b)) => a.partial_cmp(b),
251 }
252 }
253}
254
255impl AsPattern for Term {
265 type Ground = GroundTerm;
266 type Var = BlankId;
267
268 fn as_pattern(&self) -> Pattern<&GroundTerm, &BlankId> {
269 match self {
270 Self::Ground(g) => Pattern::Ground(g),
271 Self::BlankId(x) => Pattern::Var(x),
272 }
273 }
274
275 fn is_ground(&self) -> bool {
276 matches!(self, Self::Ground(_))
277 }
278
279 fn is_var(&self) -> bool {
280 matches!(self, Self::BlankId(_))
281 }
282}