1use crate::object::{InvalidExpandedJson, TryFromJson};
2use crate::Term;
3use contextual::{AsRefWithContext, DisplayWithContext, WithContext};
4use hashbrown::HashMap;
5use iref::{Iri, IriBuf};
6use json_ld_syntax::IntoJsonWithContext;
7use rdf_types::{
8 vocabulary::{BlankIdVocabulary, IriVocabulary},
9 BlankId, BlankIdBuf, Generator, InvalidBlankId, Vocabulary, VocabularyMut,
10};
11use std::convert::TryFrom;
12use std::fmt;
13use std::hash::Hash;
14
15pub use rdf_types::Id as ValidId;
16
17pub type ValidVocabularyId<V> =
18 ValidId<<V as IriVocabulary>::Iri, <V as BlankIdVocabulary>::BlankId>;
19
20pub type VocabularyId<V> = Id<<V as IriVocabulary>::Iri, <V as BlankIdVocabulary>::BlankId>;
21
22#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
37pub enum Id<I = IriBuf, B = BlankIdBuf> {
38 Valid(ValidId<I, B>),
40
41 Invalid(String),
43}
44
45#[allow(clippy::derived_hash_with_manual_eq)]
46impl<I: Hash, B: Hash> Hash for Id<I, B> {
47 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
48 match self {
49 Self::Valid(id) => id.hash(state),
50 Self::Invalid(id) => id.hash(state),
51 }
52 }
53}
54
55impl<I: PartialEq, B: PartialEq> indexmap::Equivalent<Id<I, B>> for ValidId<I, B> {
56 fn equivalent(&self, key: &Id<I, B>) -> bool {
57 match key {
58 Id::Valid(id) => self == id,
59 _ => false,
60 }
61 }
62}
63
64impl<'a, B> indexmap::Equivalent<Id<IriBuf, B>> for &'a Iri {
65 fn equivalent(&self, key: &Id<IriBuf, B>) -> bool {
66 match key {
67 Id::Valid(ValidId::Iri(iri)) => *self == iri,
68 _ => false,
69 }
70 }
71}
72
73impl<B> indexmap::Equivalent<Id<IriBuf, B>> for iref::IriBuf {
74 fn equivalent(&self, key: &Id<IriBuf, B>) -> bool {
75 match key {
76 Id::Valid(ValidId::Iri(iri)) => self == iri,
77 _ => false,
78 }
79 }
80}
81
82impl<I> indexmap::Equivalent<Id<I, BlankIdBuf>> for rdf_types::BlankId {
83 fn equivalent(&self, key: &Id<I, BlankIdBuf>) -> bool {
84 match key {
85 Id::Valid(ValidId::Blank(b)) => self == b,
86 _ => false,
87 }
88 }
89}
90
91impl<I> indexmap::Equivalent<Id<I, BlankIdBuf>> for rdf_types::BlankIdBuf {
92 fn equivalent(&self, key: &Id<I, BlankIdBuf>) -> bool {
93 match key {
94 Id::Valid(ValidId::Blank(b)) => self == b,
95 _ => false,
96 }
97 }
98}
99
100impl<I, B> TryFromJson<I, B> for Id<I, B> {
101 fn try_from_json_in(
102 vocabulary: &mut impl VocabularyMut<Iri = I, BlankId = B>,
103 value: json_syntax::Value,
104 ) -> Result<Self, InvalidExpandedJson> {
105 match value {
106 json_syntax::Value::String(s) => match Iri::new(s.as_str()) {
107 Ok(iri) => Ok(Self::Valid(ValidId::Iri(vocabulary.insert(iri)))),
108 Err(_) => match BlankId::new(s.as_str()) {
109 Ok(blank_id) => Ok(Self::Valid(ValidId::Blank(
110 vocabulary.insert_blank_id(blank_id),
111 ))),
112 Err(_) => Ok(Self::Invalid(s.to_string())),
113 },
114 },
115 _ => Err(InvalidExpandedJson::InvalidId),
116 }
117 }
118}
119
120impl<I: From<IriBuf>, B: From<BlankIdBuf>> Id<I, B> {
121 pub fn from_string(s: String) -> Self {
122 match IriBuf::new(s) {
123 Ok(iri) => Self::Valid(ValidId::Iri(iri.into())),
124 Err(e) => match BlankIdBuf::new(e.0) {
125 Ok(blank) => Self::Valid(ValidId::Blank(blank.into())),
126 Err(InvalidBlankId(s)) => Self::Invalid(s),
127 },
128 }
129 }
130}
131
132impl<I, B> Id<I, B> {
133 pub fn iri(iri: I) -> Self {
134 Self::Valid(ValidId::Iri(iri))
135 }
136
137 pub fn blank(b: B) -> Self {
138 Self::Valid(ValidId::Blank(b))
139 }
140
141 pub fn from_string_in(
142 vocabulary: &mut impl VocabularyMut<Iri = I, BlankId = B>,
143 s: String,
144 ) -> Self {
145 match Iri::new(&s) {
146 Ok(iri) => Self::Valid(ValidId::Iri(vocabulary.insert(iri))),
147 Err(_) => match BlankId::new(&s) {
148 Ok(blank) => Self::Valid(ValidId::Blank(vocabulary.insert_blank_id(blank))),
149 Err(_) => Self::Invalid(s),
150 },
151 }
152 }
153
154 #[inline(always)]
159 pub fn is_valid(&self) -> bool {
160 !matches!(self, Self::Invalid(_))
161 }
162
163 pub fn into_blank(self) -> Option<B> {
164 match self {
165 Self::Valid(ValidId::Blank(b)) => Some(b),
166 _ => None,
167 }
168 }
169
170 #[inline(always)]
171 pub fn is_blank(&self) -> bool {
172 matches!(self, Id::Valid(ValidId::Blank(_)))
173 }
174
175 #[inline(always)]
176 pub fn as_blank(&self) -> Option<&B> {
177 match self {
178 Id::Valid(ValidId::Blank(k)) => Some(k),
179 _ => None,
180 }
181 }
182
183 #[inline(always)]
184 pub fn is_iri(&self) -> bool {
185 matches!(self, Id::Valid(ValidId::Iri(_)))
186 }
187
188 #[inline(always)]
189 pub fn as_iri(&self) -> Option<&I> {
190 match self {
191 Id::Valid(ValidId::Iri(k)) => Some(k),
192 _ => None,
193 }
194 }
195
196 #[inline(always)]
197 pub fn into_term(self) -> Term<I, B> {
198 Term::Id(self)
199 }
200
201 pub fn as_ref(&self) -> Ref<I, B> {
202 match self {
203 Self::Valid(ValidId::Iri(t)) => Ref::Iri(t),
204 Self::Valid(ValidId::Blank(id)) => Ref::Blank(id),
205 Self::Invalid(id) => Ref::Invalid(id.as_str()),
206 }
207 }
208
209 pub fn map<J, C>(self, f: impl FnOnce(rdf_types::Id<I, B>) -> rdf_types::Id<J, C>) -> Id<J, C> {
210 match self {
211 Self::Valid(id) => Id::Valid(f(id)),
212 Self::Invalid(id) => Id::Invalid(id),
213 }
214 }
215}
216
217impl<I: AsRef<str>, B: AsRef<str>> Id<I, B> {
218 #[inline(always)]
222 pub fn as_str(&self) -> &str {
223 match self {
224 Id::Valid(ValidId::Iri(id)) => id.as_ref(),
225 Id::Valid(ValidId::Blank(id)) => id.as_ref(),
226 Id::Invalid(id) => id.as_str(),
227 }
228 }
229}
230
231impl<T, B, N: Vocabulary<Iri = T, BlankId = B>> AsRefWithContext<str, N> for Id<T, B> {
232 fn as_ref_with<'a>(&'a self, vocabulary: &'a N) -> &'a str {
233 match self {
234 Id::Valid(ValidId::Iri(id)) => vocabulary.iri(id).unwrap().as_str(),
235 Id::Valid(ValidId::Blank(id)) => vocabulary.blank_id(id).unwrap().as_str(),
236 Id::Invalid(id) => id.as_str(),
237 }
238 }
239}
240
241impl<I: PartialEq, B> PartialEq<I> for Id<I, B> {
242 fn eq(&self, other: &I) -> bool {
243 match self {
244 Id::Valid(ValidId::Iri(id)) => id == other,
245 _ => false,
246 }
247 }
248}
249
250impl<T: PartialEq<str>, B: PartialEq<str>> PartialEq<str> for Id<T, B> {
251 fn eq(&self, other: &str) -> bool {
252 match self {
253 Id::Valid(ValidId::Iri(iri)) => iri == other,
254 Id::Valid(ValidId::Blank(blank)) => blank == other,
255 Id::Invalid(id) => id == other,
256 }
257 }
258}
259
260impl<'a, T, B> From<&'a Id<T, B>> for Id<&'a T, &'a B> {
261 fn from(r: &'a Id<T, B>) -> Id<&'a T, &'a B> {
262 match r {
263 Id::Valid(ValidId::Iri(id)) => Id::Valid(ValidId::Iri(id)),
264 Id::Valid(ValidId::Blank(id)) => Id::Valid(ValidId::Blank(id)),
265 Id::Invalid(id) => Id::Invalid(id.clone()),
266 }
267 }
268}
269
270impl<T, B> From<T> for Id<T, B> {
271 #[inline(always)]
272 fn from(id: T) -> Id<T, B> {
273 Id::Valid(ValidId::Iri(id))
274 }
275}
276
277impl<T: PartialEq, B: PartialEq> PartialEq<Term<T, B>> for Id<T, B> {
278 #[inline]
279 fn eq(&self, term: &Term<T, B>) -> bool {
280 match term {
281 Term::Id(prop) => self == prop,
282 _ => false,
283 }
284 }
285}
286
287impl<T: PartialEq, B: PartialEq> PartialEq<Id<T, B>> for Term<T, B> {
288 #[inline]
289 fn eq(&self, r: &Id<T, B>) -> bool {
290 match self {
291 Term::Id(prop) => prop == r,
292 _ => false,
293 }
294 }
295}
296
297impl<T, B> TryFrom<Term<T, B>> for Id<T, B> {
298 type Error = Term<T, B>;
299
300 #[inline]
301 fn try_from(term: Term<T, B>) -> Result<Id<T, B>, Term<T, B>> {
302 match term {
303 Term::Id(prop) => Ok(prop),
304 term => Err(term),
305 }
306 }
307}
308
309impl<T: fmt::Display, B: fmt::Display> fmt::Display for Id<T, B> {
310 #[inline]
311 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
312 match self {
313 Id::Valid(id) => id.fmt(f),
314 Id::Invalid(id) => id.fmt(f),
315 }
316 }
317}
318
319impl<V: IriVocabulary + BlankIdVocabulary> DisplayWithContext<V> for Id<V::Iri, V::BlankId> {
320 fn fmt_with(&self, vocabulary: &V, f: &mut fmt::Formatter) -> fmt::Result {
321 use fmt::Display;
322 match self {
323 Id::Valid(id) => id.fmt_with(vocabulary, f),
324 Id::Invalid(id) => id.fmt(f),
325 }
326 }
327}
328
329impl<T: fmt::Debug, B: fmt::Debug> fmt::Debug for Id<T, B> {
330 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
331 match self {
332 Id::Valid(id) => write!(f, "Id::Valid({id:?})"),
333 Id::Invalid(id) => write!(f, "Id::Invalid({id:?})"),
334 }
335 }
336}
337
338impl<T, B, N: Vocabulary<Iri = T, BlankId = B>> IntoJsonWithContext<N> for Id<T, B> {
339 fn into_json_with(self, context: &N) -> json_syntax::Value {
340 self.into_with(context).to_string().into()
341 }
342}
343
344impl<T, B> From<ValidId<T, B>> for Id<T, B> {
345 fn from(r: ValidId<T, B>) -> Self {
346 Id::Valid(r)
347 }
348}
349
350impl<T, B> TryFrom<Id<T, B>> for ValidId<T, B> {
351 type Error = String;
352
353 fn try_from(r: Id<T, B>) -> Result<Self, Self::Error> {
354 match r {
355 Id::Valid(r) => Ok(r),
356 Id::Invalid(id) => Err(id),
357 }
358 }
359}
360
361impl<'a, T, B> TryFrom<&'a Id<T, B>> for &'a ValidId<T, B> {
362 type Error = &'a String;
363
364 fn try_from(r: &'a Id<T, B>) -> Result<Self, Self::Error> {
365 match r {
366 Id::Valid(r) => Ok(r),
367 Id::Invalid(id) => Err(id),
368 }
369 }
370}
371
372impl<'a, T, B> TryFrom<&'a mut Id<T, B>> for &'a mut ValidId<T, B> {
373 type Error = &'a mut String;
374
375 fn try_from(r: &'a mut Id<T, B>) -> Result<Self, Self::Error> {
376 match r {
377 Id::Valid(r) => Ok(r),
378 Id::Invalid(id) => Err(id),
379 }
380 }
381}
382
383#[derive(Clone, PartialEq, Eq, Hash)]
385#[repr(u8)]
386pub enum Ref<'a, T = IriBuf, B = BlankIdBuf> {
387 Iri(&'a T),
389
390 Blank(&'a B),
392
393 Invalid(&'a str),
395}
396
397pub trait IdentifyAll<T, B> {
398 fn identify_all_with<N: Vocabulary<Iri = T, BlankId = B>, G: Generator<N>>(
399 &mut self,
400 vocabulary: &mut N,
401 generator: &mut G,
402 ) where
403 T: Eq + Hash,
404 B: Eq + Hash;
405
406 fn identify_all<G: Generator>(&mut self, generator: &mut G)
407 where
408 T: Eq + Hash,
409 B: Eq + Hash,
410 (): Vocabulary<Iri = T, BlankId = B>,
411 {
412 self.identify_all_with(rdf_types::vocabulary::no_vocabulary_mut(), generator)
413 }
414}
415
416pub trait Relabel<T, B> {
417 fn relabel_with<N: Vocabulary<Iri = T, BlankId = B>, G: Generator<N>>(
418 &mut self,
419 vocabulary: &mut N,
420 generator: &mut G,
421 relabeling: &mut HashMap<B, ValidId<T, B>>,
422 ) where
423 T: Clone + Eq + Hash,
424 B: Clone + Eq + Hash;
425
426 fn relabel<G: Generator>(
427 &mut self,
428 generator: &mut G,
429 relabeling: &mut HashMap<B, ValidId<T, B>>,
430 ) where
431 T: Clone + Eq + Hash,
432 B: Clone + Eq + Hash,
433 (): Vocabulary<Iri = T, BlankId = B>,
434 {
435 self.relabel_with(
436 rdf_types::vocabulary::no_vocabulary_mut(),
437 generator,
438 relabeling,
439 )
440 }
441}