Skip to main content

jsonld_syntax/context/term_definition/
id.rs

1use crate::{CompactIri, ExpandableRef, Keyword, context::definition::KeyOrKeywordRef};
2use iri_rs::Iri;
3use rdfx::BlankId;
4use std::{fmt, hash::Hash};
5
6#[derive(Clone, PartialOrd, Ord, Debug)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8#[cfg_attr(feature = "serde", serde(untagged))]
9/// Value of the `@id` entry of a term definition.
10pub enum Id {
11    /// A JSON-LD keyword, which makes the term an alias of that keyword.
12    Keyword(Keyword),
13    /// Anything else: an IRI, a compact IRI, a blank node identifier or another
14    /// term of the context. Kept unvalidated, as telling those apart requires
15    /// the processed context.
16    Term(String),
17}
18
19impl Id {
20    /// Parses this value as an IRI, returning `None` if it is not one.
21    #[must_use]
22    pub fn as_iri(&self) -> Option<Iri<&str>> {
23        match self {
24            Self::Term(t) => Iri::parse(t.as_str()).ok(),
25            Self::Keyword(_) => None,
26        }
27    }
28
29    /// Parses this value as a blank node identifier, returning `None` if it is
30    /// not one.
31    #[must_use]
32    pub fn as_blank_id(&self) -> Option<&BlankId> {
33        match self {
34            Self::Term(t) => BlankId::new(t).ok(),
35            Self::Keyword(_) => None,
36        }
37    }
38
39    /// Parses this value as a compact IRI, returning `None` if it is not one.
40    #[must_use]
41    pub fn as_compact_iri(&self) -> Option<&CompactIri> {
42        match self {
43            Self::Term(t) => CompactIri::new(t).ok(),
44            Self::Keyword(_) => None,
45        }
46    }
47
48    /// Returns the keyword, or `None` if this value is not one.
49    #[must_use]
50    pub fn as_keyword(&self) -> Option<Keyword> {
51        match self {
52            Self::Keyword(k) => Some(*k),
53            Self::Term(_) => None,
54        }
55    }
56
57    /// Returns this value as it is spelled in the context.
58    #[must_use]
59    pub fn as_str(&self) -> &str {
60        match self {
61            Self::Term(t) => t.as_str(),
62            Self::Keyword(k) => k.into_str(),
63        }
64    }
65
66    /// Converts this value into an owned `String`, allocating if it is a
67    /// keyword.
68    #[must_use]
69    pub fn into_string(self) -> String {
70        match self {
71            Self::Term(t) => t,
72            Self::Keyword(k) => k.to_string(),
73        }
74    }
75
76    /// Checks whether this value is a JSON-LD keyword.
77    #[must_use]
78    pub fn is_keyword(&self) -> bool {
79        matches!(self, Self::Keyword(_))
80    }
81
82    /// Checks whether this value is keyword-like: an `@` followed by ASCII
83    /// letters. See [`crate::is_keyword_like`].
84    #[must_use]
85    pub fn is_keyword_like(&self) -> bool {
86        crate::is_keyword_like(self.as_str())
87    }
88
89    /// Returns a borrowed view of this value.
90    #[must_use]
91    pub fn as_id_ref(&self) -> IdRef<'_> {
92        match self {
93            Self::Term(t) => IdRef::Term(t),
94            Self::Keyword(k) => IdRef::Keyword(*k),
95        }
96    }
97}
98
99impl PartialEq for Id {
100    fn eq(&self, other: &Self) -> bool {
101        match (self, other) {
102            (Self::Term(a), Self::Term(b)) => a == b,
103            (Self::Keyword(a), Self::Keyword(b)) => a == b,
104            _ => false,
105        }
106    }
107}
108
109impl Eq for Id {}
110
111impl Hash for Id {
112    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
113        self.as_str().hash(state);
114    }
115}
116
117impl From<String> for Id {
118    fn from(s: String) -> Self {
119        match Keyword::try_from(s.as_str()) {
120            Ok(k) => Self::Keyword(k),
121            Err(_) => Self::Term(s),
122        }
123    }
124}
125
126impl<'a> From<&'a Id> for ExpandableRef<'a> {
127    fn from(i: &'a Id) -> Self {
128        match i {
129            Id::Term(t) => Self::String(t),
130            Id::Keyword(k) => Self::Keyword(*k),
131        }
132    }
133}
134
135impl fmt::Display for Id {
136    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
137        match self {
138            Self::Term(t) => t.fmt(f),
139            Self::Keyword(k) => k.fmt(f),
140        }
141    }
142}
143
144#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
145/// Borrowed value of the `@id` entry of a term definition.
146pub enum IdRef<'a> {
147    /// An IRI, a compact IRI, a blank node identifier or another term of the
148    /// context.
149    Term(&'a str),
150    /// A JSON-LD keyword, which makes the term an alias of that keyword.
151    Keyword(Keyword),
152}
153
154impl IdRef<'_> {
155    /// Returns this value as it is spelled in the context.
156    #[must_use]
157    pub fn as_str(&self) -> &str {
158        match self {
159            Self::Term(t) => t,
160            Self::Keyword(k) => k.into_str(),
161        }
162    }
163
164    /// Checks whether this value is a JSON-LD keyword.
165    #[must_use]
166    pub fn is_keyword(&self) -> bool {
167        matches!(self, Self::Keyword(_))
168    }
169
170    /// Checks whether this value is keyword-like: an `@` followed by ASCII
171    /// letters. See [`crate::is_keyword_like`].
172    #[must_use]
173    pub fn is_keyword_like(&self) -> bool {
174        crate::is_keyword_like(self.as_str())
175    }
176}
177
178impl<'a> From<&'a str> for IdRef<'a> {
179    fn from(s: &'a str) -> Self {
180        match Keyword::try_from(s) {
181            Ok(k) => Self::Keyword(k),
182            Err(_) => Self::Term(s),
183        }
184    }
185}
186
187impl<'a> From<IdRef<'a>> for ExpandableRef<'a> {
188    fn from(i: IdRef<'a>) -> Self {
189        match i {
190            IdRef::Term(t) => Self::String(t),
191            IdRef::Keyword(k) => Self::Keyword(k),
192        }
193    }
194}
195
196impl fmt::Display for IdRef<'_> {
197    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198        self.as_str().fmt(f)
199    }
200}
201
202impl<'a> From<IdRef<'a>> for KeyOrKeywordRef<'a> {
203    fn from(i: IdRef<'a>) -> Self {
204        match i {
205            IdRef::Term(t) => Self::Key(t.into()),
206            IdRef::Keyword(k) => Self::Keyword(k),
207        }
208    }
209}