Skip to main content

json_ld/syntax/
keyword.rs

1use std::borrow::Borrow;
2use std::convert::TryFrom;
3use std::fmt;
4use std::str::FromStr;
5
6#[derive(Clone, Copy, Debug)]
7pub struct NotAJsonLdKeyword<T = String>(pub T);
8
9impl<T: ?Sized + ToOwned> NotAJsonLdKeyword<&T> {
10	pub fn into_owned(self) -> NotAJsonLdKeyword<T::Owned> {
11		NotAJsonLdKeyword(self.0.to_owned())
12	}
13}
14
15macro_rules! keyword {
16	{
17		$(
18			$(#[$meta:meta])*
19			$ident:ident : $lit:literal
20		),*
21	} => {
22		/// JSON-LD keywords.
23		#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
24		#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25		pub enum JsonLdKeyword {
26			$(
27				$(#[$meta])*
28				#[cfg_attr(feature = "serde", serde(rename = $lit))]
29				$ident
30			),*
31		}
32
33		impl JsonLdKeyword {
34			pub fn into_str(self) -> &'static str {
35				match self {
36					$(
37						Self::$ident => $lit
38					),*
39				}
40			}
41		}
42
43		impl<'a> TryFrom<&'a str> for JsonLdKeyword {
44			type Error = NotAJsonLdKeyword<&'a str>;
45
46			fn try_from(input: &'a str) -> Result<JsonLdKeyword, NotAJsonLdKeyword<&'a str>> {
47				match input {
48					$(
49						$lit => Ok(Self::$ident),
50					)*
51					_ => Err(NotAJsonLdKeyword(input))
52				}
53			}
54		}
55    };
56}
57
58keyword! {
59	/// `@base`.
60	/// Used to set the base IRI against which to resolve those relative IRI references
61	/// which are otherwise interpreted relative to the document.
62	Base : "@base",
63
64	/// `@container`.
65	/// Used to set the default container type for a term.
66	Container : "@container",
67
68	/// `@context`.
69	/// Used to define the short-hand names that are used throughout a JSON-LD document.
70	Context : "@context",
71
72	/// `@direction`.
73	/// Used to set the base direction of a JSON-LD value, which are not typed values.
74	/// (e.g. strings, or language-tagged strings).
75	Direction : "@direction",
76
77	/// `@graph`.
78	/// Used to express a graph.
79	Graph : "@graph",
80
81	/// `@id`.
82	/// Used to uniquely identify node objects that are being described in the document with IRIs
83	/// or blank node identifiers.
84	Id : "@id",
85
86	/// `@import`.
87	/// Used in a context definition to load an external context within which the containing
88	/// context definition is merged.
89	Import : "@import",
90
91	/// `@included`.
92	/// Used in a top-level node object to define an included block, for including secondary node
93	/// objects within another node object.
94	Included : "@included",
95
96	/// `@index`.
97	/// Used to specify that a container is used to index information and that processing should
98	/// continue deeper into a JSON data structure.
99	Index : "@index",
100
101	/// `@json`.
102	/// Used as the @type value of a JSON literal.
103	Json : "@json",
104
105	/// `@language`.
106	/// Used to specify the language for a particular string value or the default language of a
107	/// JSON-LD document.
108	Language : "@language",
109
110	/// `@list`.
111	/// Used to express an ordered set of data.
112	List : "@list",
113
114	/// `@nest`.
115	/// Used to define a property of a node object that groups together properties of that node,
116	/// but is not an edge in the graph.
117	Nest : "@nest",
118
119	/// `@none`.
120	/// Used as an index value in an index map, id map, language map, type map, or elsewhere where
121	/// a map is used to index into other values, when the indexed node does not have the feature
122	/// being indexed.
123	None : "@none",
124
125	/// `@prefix`.
126	/// With the value true, allows this term to be used to construct a compact IRI when
127	/// compacting.
128	Prefix : "@prefix",
129
130	/// `@propagate`.
131	/// Used in a context definition to change the scope of that context.
132	///
133	/// By default, it is true, meaning that contexts propagate across node objects
134	/// (other than for type-scoped contexts, which default to false).
135	/// Setting this to false causes term definitions created within that context to be removed
136	/// when entering a new node object.
137	Propagate : "@propagate",
138
139	/// `@protected`.
140	/// Used to prevent term definitions of a context to be overridden by other contexts.
141	Protected : "@protected",
142
143	/// `@reverse`.
144	/// Used to express reverse properties.
145	Reverse : "@reverse",
146
147	/// `@set`.
148	/// Used to express an unordered set of data and to ensure that values are always represented
149	/// as arrays.
150	Set : "@set",
151
152	/// `@type`.
153	/// Used to set the type of a node or the datatype of a typed value.
154	Type : "@type",
155
156	/// `@value`.
157	/// Used to specify the data that is associated with a particular property in the graph.
158	Value : "@value",
159
160	/// `@version`.
161	/// Used in a context definition to set the processing mode.
162	Version : "@version",
163
164	/// `@vocab`.
165	/// Used to expand properties and values in @type with a common prefix IRI.
166	Vocab : "@vocab"
167}
168
169impl JsonLdKeyword {
170	pub fn as_str(&self) -> &'static str {
171		self.into_str()
172	}
173}
174
175impl FromStr for JsonLdKeyword {
176	type Err = NotAJsonLdKeyword;
177
178	fn from_str(s: &str) -> Result<Self, Self::Err> {
179		Self::try_from(s).map_err(NotAJsonLdKeyword::into_owned)
180	}
181}
182
183impl<'a> From<JsonLdKeyword> for &'a str {
184	fn from(k: JsonLdKeyword) -> &'a str {
185		k.into_str()
186	}
187}
188
189impl fmt::Display for JsonLdKeyword {
190	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
191		self.into_str().fmt(f)
192	}
193}
194
195impl PartialEq<str> for JsonLdKeyword {
196	fn eq(&self, other: &str) -> bool {
197		self.as_str() == other
198	}
199}
200
201impl PartialEq<&str> for JsonLdKeyword {
202	fn eq(&self, other: &&str) -> bool {
203		self.as_str() == *other
204	}
205}
206
207impl PartialEq<JsonLdKeyword> for str {
208	fn eq(&self, other: &JsonLdKeyword) -> bool {
209		self == other.as_str()
210	}
211}
212
213impl PartialEq<JsonLdKeyword> for &str {
214	fn eq(&self, other: &JsonLdKeyword) -> bool {
215		*self == other.as_str()
216	}
217}
218
219pub fn is_keyword(str: &str) -> bool {
220	JsonLdKeyword::try_from(str).is_ok()
221}
222
223fn is_alpha(c: char) -> bool {
224	let c = c as u32;
225	(0x41..=0x5a).contains(&c) || (0x61..=0x7a).contains(&c)
226}
227
228pub fn is_keyword_like(s: &str) -> bool {
229	if s.len() > 1 {
230		for (i, c) in s.chars().enumerate() {
231			if (i == 0 && c != '@') || (i > 0 && !is_alpha(c)) {
232				return false;
233			}
234		}
235
236		true
237	} else {
238		false
239	}
240}
241
242#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
243pub struct JsonLdKeywordType;
244
245impl JsonLdKeywordType {
246	pub fn as_str(&self) -> &'static str {
247		"@type"
248	}
249}
250
251impl Borrow<str> for JsonLdKeywordType {
252	fn borrow(&self) -> &str {
253		self.as_str()
254	}
255}