1use iref::{Iri, IriBuf};
2use std::{cmp::Ordering, fmt, hash::Hash};
3
4use crate::{
5 vocabulary::{
6 BlankIdVocabulary, ByRef, EmbedIntoVocabulary, EmbeddedIntoVocabulary,
7 ExtractFromVocabulary, ExtractedFromVocabulary, IriVocabulary,
8 },
9 BlankId, BlankIdBuf, LexicalGraphLabelRef, LexicalSubjectRef, MaybeBlankId, MaybeIri,
10 RdfDisplay, Term, TryAsBlankId, TryAsIri, TryIntoBlankId, TryIntoIri, Vocabulary,
11 VocabularyMut,
12};
13
14#[derive(Clone, Copy, Eq, Ord, Debug)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25pub enum Id<I = IriBuf, B = BlankIdBuf> {
26 Blank(B),
28
29 Iri(I),
31}
32
33pub type LexicalIdRef<'a> = Id<&'a Iri, &'a BlankId>;
35
36impl<I, B> Id<I, B> {
37 pub fn is_blank(&self) -> bool {
38 matches!(self, Self::Blank(_))
39 }
40
41 pub fn is_iri(&self) -> bool {
42 matches!(self, Self::Iri(_))
43 }
44
45 pub fn as_blank(&self) -> Option<&B> {
46 match self {
47 Self::Blank(id) => Some(id),
48 _ => None,
49 }
50 }
51
52 pub fn as_iri(&self) -> Option<&I> {
53 match self {
54 Self::Iri(iri) => Some(iri),
55 _ => None,
56 }
57 }
58
59 pub fn try_into_blank(self) -> Result<B, I> {
60 match self {
61 Self::Blank(id) => Ok(id),
62 Self::Iri(iri) => Err(iri),
63 }
64 }
65
66 pub fn into_blank(self) -> Option<B> {
67 self.try_into_blank().ok()
68 }
69
70 pub fn try_into_iri(self) -> Result<I, B> {
71 match self {
72 Self::Iri(iri) => Ok(iri),
73 Self::Blank(b) => Err(b),
74 }
75 }
76
77 pub fn into_iri(self) -> Option<I> {
78 self.try_into_iri().ok()
79 }
80
81 pub fn as_term<L>(&self) -> Term<&Self, &L> {
83 Term::Id(self)
84 }
85
86 pub fn into_term<L>(self) -> Term<Self, L> {
88 Term::Id(self)
89 }
90
91 pub fn as_str(&self) -> &str
93 where
94 I: AsRef<str>,
95 B: AsRef<str>,
96 {
97 match self {
98 Self::Iri(i) => i.as_ref(),
99 Self::Blank(i) => i.as_ref(),
100 }
101 }
102
103 pub fn as_ref(&self) -> Id<&I, &B> {
105 match self {
106 Self::Iri(i) => Id::Iri(i),
107 Self::Blank(b) => Id::Blank(b),
108 }
109 }
110}
111
112impl<V, I: EmbedIntoVocabulary<V>, B: EmbedIntoVocabulary<V>> EmbedIntoVocabulary<V> for Id<I, B> {
113 type Embedded = Id<I::Embedded, B::Embedded>;
114
115 fn embed_into_vocabulary(self, vocabulary: &mut V) -> Self::Embedded {
116 match self {
117 Self::Iri(i) => Id::Iri(i.embed_into_vocabulary(vocabulary)),
118 Self::Blank(b) => Id::Blank(b.embed_into_vocabulary(vocabulary)),
119 }
120 }
121}
122
123impl<V, I: EmbeddedIntoVocabulary<V>, B: EmbeddedIntoVocabulary<V>> EmbeddedIntoVocabulary<V>
124 for Id<I, B>
125{
126 type Embedded = Id<I::Embedded, B::Embedded>;
127
128 fn embedded_into_vocabulary(&self, vocabulary: &mut V) -> Self::Embedded {
129 match self {
130 Self::Iri(i) => Id::Iri(i.embedded_into_vocabulary(vocabulary)),
131 Self::Blank(b) => Id::Blank(b.embedded_into_vocabulary(vocabulary)),
132 }
133 }
134}
135
136impl<V: IriVocabulary + BlankIdVocabulary> ExtractedFromVocabulary<V> for Id<V::Iri, V::BlankId> {
137 type Extracted = Id<IriBuf, BlankIdBuf>;
138
139 fn extracted_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted {
140 match self {
141 Self::Iri(i) => Id::Iri(vocabulary.iri(i).unwrap().to_owned()),
142 Self::Blank(b) => Id::Blank(vocabulary.blank_id(b).unwrap().to_owned()),
143 }
144 }
145}
146
147impl<V: IriVocabulary + BlankIdVocabulary> ExtractFromVocabulary<V> for Id<V::Iri, V::BlankId> {
148 type Extracted = Id<IriBuf, BlankIdBuf>;
149
150 fn extract_from_vocabulary(self, vocabulary: &V) -> Self::Extracted {
151 match self {
152 Self::Iri(i) => Id::Iri(vocabulary.owned_iri(i).ok().unwrap()),
153 Self::Blank(b) => Id::Blank(vocabulary.owned_blank_id(b).ok().unwrap()),
154 }
155 }
156}
157
158impl<'a, V: IriVocabulary + BlankIdVocabulary> ExtractFromVocabulary<V>
159 for ByRef<Id<&'a V::Iri, &'a V::BlankId>>
160{
161 type Extracted = Id<IriBuf, BlankIdBuf>;
162
163 fn extract_from_vocabulary(self, vocabulary: &V) -> Self::Extracted {
164 match self.0 {
165 Id::Iri(i) => Id::Iri(vocabulary.iri(i).unwrap().to_owned()),
166 Id::Blank(b) => Id::Blank(vocabulary.blank_id(b).unwrap().to_owned()),
167 }
168 }
169}
170
171pub trait TryExportId<I, B> {
173 type Error;
174
175 fn try_export_id(&self, id: Id<I, B>) -> Result<Id, Self::Error>;
177}
178
179impl<V: Vocabulary> TryExportId<V::Iri, V::BlankId> for V {
180 type Error = Id<V::Iri, V::BlankId>;
181
182 fn try_export_id(&self, id: Id<V::Iri, V::BlankId>) -> Result<Id, Self::Error> {
183 match id {
184 Id::Iri(i) => self.owned_iri(i).map(Id::Iri).map_err(Id::Iri),
185 Id::Blank(b) => self.owned_blank_id(b).map(Id::Blank).map_err(Id::Blank),
186 }
187 }
188}
189
190impl<'a, I, B> Id<&'a I, &'a B> {
191 pub fn cloned(self) -> Id<I, B>
194 where
195 I: Clone,
196 B: Clone,
197 {
198 match self {
199 Self::Iri(i) => Id::Iri(i.clone()),
200 Self::Blank(b) => Id::Blank(b.clone()),
201 }
202 }
203
204 pub fn copied(self) -> Id<I, B>
207 where
208 I: Copy,
209 B: Copy,
210 {
211 match self {
212 Self::Iri(i) => Id::Iri(*i),
213 Self::Blank(b) => Id::Blank(*b),
214 }
215 }
216}
217
218impl Id {
219 #[inline(always)]
221 pub fn as_lexical_id_ref(&self) -> LexicalIdRef {
222 match self {
223 Self::Iri(i) => Id::Iri(i.as_iri()),
224 Self::Blank(b) => Id::Blank(b.as_blank_id_ref()),
225 }
226 }
227
228 #[inline(always)]
230 pub fn as_lexical_subject_ref(&self) -> LexicalSubjectRef {
231 self.as_lexical_id_ref()
232 }
233
234 #[inline(always)]
236 pub fn as_graph_label_ref(&self) -> LexicalGraphLabelRef {
237 self.as_lexical_id_ref()
238 }
239
240 pub fn inserted_into<V: VocabularyMut>(&self, vocabulary: &mut V) -> Id<V::Iri, V::BlankId> {
241 match self {
242 Self::Blank(b) => Id::Blank(vocabulary.insert_blank_id(b.as_blank_id_ref())),
243 Self::Iri(i) => Id::Iri(vocabulary.insert(i.as_iri())),
244 }
245 }
246
247 pub fn insert_into<V: VocabularyMut>(self, vocabulary: &mut V) -> Id<V::Iri, V::BlankId> {
248 match self {
249 Self::Blank(b) => Id::Blank(vocabulary.insert_blank_id(b.as_blank_id_ref())),
250 Self::Iri(i) => Id::Iri(vocabulary.insert(i.as_iri())),
251 }
252 }
253}
254
255impl LexicalIdRef<'_> {
256 #[inline(always)]
257 pub fn into_owned(self) -> Id {
258 match self {
259 Self::Iri(i) => Id::Iri(i.to_owned()),
260 Self::Blank(b) => Id::Blank(b.to_owned()),
261 }
262 }
263}
264
265impl<I: Hash, B: Hash> Hash for Id<I, B> {
266 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
267 match self {
268 Self::Blank(id) => id.hash(state),
269 Self::Iri(i) => i.hash(state),
270 }
271 }
272}
273
274impl<I1: PartialEq<I2>, B1: PartialEq<B2>, I2, B2> PartialEq<Id<I2, B2>> for Id<I1, B1> {
275 fn eq(&self, other: &Id<I2, B2>) -> bool {
276 match (self, other) {
277 (Self::Blank(a), Id::Blank(b)) => a == b,
278 (Self::Iri(a), Id::Iri(b)) => a == b,
279 _ => false,
280 }
281 }
282}
283
284impl<I1: PartialOrd<I2>, B1: PartialOrd<B2>, I2, B2> PartialOrd<Id<I2, B2>> for Id<I1, B1> {
285 fn partial_cmp(&self, other: &Id<I2, B2>) -> Option<Ordering> {
286 match (self, other) {
287 (Self::Blank(a), Id::Blank(b)) => a.partial_cmp(b),
288 (Self::Blank(_), _) => Some(Ordering::Less),
289 (Self::Iri(a), Id::Iri(b)) => a.partial_cmp(b),
290 _ => Some(Ordering::Greater),
291 }
292 }
293}
294
295impl<I: fmt::Display, B: fmt::Display> fmt::Display for Id<I, B> {
296 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
297 match self {
298 Self::Blank(id) => id.fmt(f),
299 Self::Iri(iri) => write!(f, "{iri}"),
300 }
301 }
302}
303
304#[cfg(feature = "contextual")]
305impl<V: crate::vocabulary::IriVocabulary + crate::vocabulary::BlankIdVocabulary>
306 contextual::DisplayWithContext<V> for Id<V::Iri, V::BlankId>
307{
308 fn fmt_with(&self, vocabulary: &V, f: &mut fmt::Formatter) -> fmt::Result {
309 use fmt::Display;
310 match self {
311 Self::Blank(id) => vocabulary.blank_id(id).unwrap().fmt(f),
312 Self::Iri(iri) => write!(f, "{}", vocabulary.iri(iri).unwrap()),
313 }
314 }
315}
316
317impl<I: fmt::Display, B: fmt::Display> RdfDisplay for Id<I, B> {
318 fn rdf_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
319 match self {
320 Self::Blank(id) => id.fmt(f),
321 Self::Iri(iri) => write!(f, "<{iri}>"),
322 }
323 }
324}
325
326#[cfg(feature = "contextual")]
327impl<V: crate::vocabulary::IriVocabulary + crate::vocabulary::BlankIdVocabulary>
328 crate::RdfDisplayWithContext<V> for Id<V::Iri, V::BlankId>
329{
330 fn rdf_fmt_with(&self, vocabulary: &V, f: &mut fmt::Formatter) -> fmt::Result {
331 use fmt::Display;
332 match self {
333 Self::Blank(id) => vocabulary.blank_id(id).unwrap().fmt(f),
334 Self::Iri(iri) => write!(f, "<{}>", vocabulary.iri(iri).unwrap()),
335 }
336 }
337}
338
339#[cfg(feature = "contextual")]
340impl<V: crate::vocabulary::IriVocabulary + crate::vocabulary::BlankIdVocabulary>
341 contextual::AsRefWithContext<str, V> for Id<V::Iri, V::BlankId>
342{
343 fn as_ref_with<'a>(&'a self, vocabulary: &'a V) -> &'a str {
344 match self {
345 Self::Blank(b) => vocabulary.blank_id(b).unwrap().as_str(),
346 Self::Iri(i) => vocabulary.iri(i).unwrap().as_str(),
347 }
348 }
349}
350
351pub trait MaybeId: MaybeIri + MaybeBlankId {}
353
354impl<T: MaybeIri + MaybeBlankId> MaybeId for T {}
355
356pub trait TryAsId: TryAsIri + TryAsBlankId {
358 fn try_as_id(&self) -> Option<Id<&Self::Iri, &Self::BlankId>> {
359 self.try_as_iri()
360 .map(Id::Iri)
361 .or_else(|| self.try_as_blank().map(Id::Blank))
362 }
363}
364
365impl<T: TryAsIri + TryAsBlankId> TryAsId for T {}
366
367pub trait TryIntoId: TryIntoIri + TryIntoBlankId {
369 fn try_into_id(self) -> Result<Id<Self::Iri, Self::BlankId>, Self> {
370 self.try_into_iri()
371 .map(Id::Iri)
372 .or_else(|t| t.try_into_blank().map(Id::Blank))
373 }
374}
375
376impl<I, B> TryIntoId for Id<I, B> {
377 fn try_into_id(self) -> Result<Self, Self> {
378 Ok(self)
379 }
380}
381
382pub trait AsId: MaybeId {
384 fn as_id(&self) -> Id<&Self::Iri, &Self::BlankId>;
385}
386
387impl<I, B> AsId for Id<I, B> {
388 fn as_id(&self) -> Id<&I, &B> {
389 self.as_ref()
390 }
391}
392
393pub trait IntoId: MaybeId {
395 fn into_id(self) -> Id<Self::Iri, Self::BlankId>;
396}
397
398impl<I, B> IntoId for Id<I, B> {
399 fn into_id(self) -> Self {
400 self
401 }
402}