jsonld_syntax/context/definition/
mod.rs1use super::{TermDefinition, term_definition};
2use crate::{Direction, Keyword, LenientLangTagBuf, Nullable, hash::IndexMap};
3use iri_rs::IriRefBuf;
4
5mod import;
6mod key;
7mod reference;
8mod type_;
9mod version;
10mod vocab;
11
12pub use import::*;
13pub use key::*;
14pub use reference::*;
15pub use type_::*;
16pub use version::*;
17pub use vocab::*;
18
19#[derive(PartialEq, Eq, Clone, Default, Debug)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25pub struct Definition {
26 #[cfg_attr(
27 feature = "serde",
28 serde(rename = "@base", default, deserialize_with = "Nullable::optional", skip_serializing_if = "Option::is_none")
29 )]
30 pub base: Option<Nullable<IriRefBuf>>,
32
33 #[cfg_attr(feature = "serde", serde(rename = "@import", default, skip_serializing_if = "Option::is_none"))]
34 pub import: Option<IriRefBuf>,
36
37 #[cfg_attr(
38 feature = "serde",
39 serde(rename = "@language", default, deserialize_with = "Nullable::optional", skip_serializing_if = "Option::is_none")
40 )]
41 pub language: Option<Nullable<LenientLangTagBuf>>,
43
44 #[cfg_attr(
45 feature = "serde",
46 serde(rename = "@direction", default, deserialize_with = "Nullable::optional", skip_serializing_if = "Option::is_none")
47 )]
48 pub direction: Option<Nullable<Direction>>,
50
51 #[cfg_attr(feature = "serde", serde(rename = "@propagate", default, skip_serializing_if = "Option::is_none"))]
52 pub propagate: Option<bool>,
54
55 #[cfg_attr(feature = "serde", serde(rename = "@protected", default, skip_serializing_if = "Option::is_none"))]
56 pub protected: Option<bool>,
58
59 #[cfg_attr(feature = "serde", serde(rename = "@type", default, skip_serializing_if = "Option::is_none"))]
60 pub type_: Option<Type>,
63
64 #[cfg_attr(feature = "serde", serde(rename = "@version", default, skip_serializing_if = "Option::is_none"))]
65 pub version: Option<Version>,
67
68 #[cfg_attr(
69 feature = "serde",
70 serde(rename = "@vocab", default, deserialize_with = "Nullable::optional", skip_serializing_if = "Option::is_none")
71 )]
72 pub vocab: Option<Nullable<Vocab>>,
74
75 #[cfg_attr(feature = "serde", serde(flatten))]
76 pub bindings: Bindings,
78}
79
80impl Definition {
81 #[must_use]
83 pub fn new() -> Self {
84 Self::default()
85 }
86
87 pub fn get(&self, key: &KeyOrKeyword) -> Option<EntryValueRef<'_>> {
92 match key {
93 KeyOrKeyword::Keyword(k) => match k {
94 Keyword::Base => self.base.as_ref().map(Nullable::as_ref).map(EntryValueRef::Base),
95 Keyword::Import => self.import.as_ref().map(EntryValueRef::Import),
96 Keyword::Language => self.language.as_ref().map(Nullable::as_ref).map(EntryValueRef::Language),
97 Keyword::Direction => self.direction.map(EntryValueRef::Direction),
98 Keyword::Propagate => self.propagate.map(EntryValueRef::Propagate),
99 Keyword::Protected => self.protected.map(EntryValueRef::Protected),
100 Keyword::Type => self.type_.map(EntryValueRef::Type),
101 Keyword::Version => self.version.map(EntryValueRef::Version),
102 Keyword::Vocab => self.vocab.as_ref().map(Nullable::as_ref).map(EntryValueRef::Vocab),
103 _ => None,
104 },
105 KeyOrKeyword::Key(k) => self.bindings.get(k).map(EntryValueRef::Definition),
106 }
107 }
108
109 #[must_use]
111 pub fn get_binding(&self, key: &Key) -> Option<Nullable<&TermDefinition>> {
112 self.bindings.get(key)
113 }
114}
115
116#[derive(PartialEq, Eq, Clone, Default, Debug)]
118#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
119#[cfg_attr(feature = "serde", serde(transparent))]
120pub struct Bindings(IndexMap<Key, Nullable<TermDefinition>>);
121
122pub struct BindingsIter<'a>(indexmap::map::Iter<'a, Key, Nullable<TermDefinition>>);
124
125impl<'a> Iterator for BindingsIter<'a> {
126 type Item = (&'a Key, Nullable<&'a TermDefinition>);
127
128 fn next(&mut self) -> Option<Self::Item> {
129 self.0.next().map(|(k, d)| (k, d.as_ref()))
130 }
131
132 fn size_hint(&self) -> (usize, Option<usize>) {
133 self.0.size_hint()
134 }
135}
136
137impl DoubleEndedIterator for BindingsIter<'_> {
138 fn next_back(&mut self) -> Option<Self::Item> {
139 self.0.next_back().map(|(k, d)| (k, d.as_ref()))
140 }
141}
142
143impl ExactSizeIterator for BindingsIter<'_> {}
144
145impl Bindings {
146 pub fn insert(&mut self, key: Key, def: Nullable<TermDefinition>) -> Option<Nullable<TermDefinition>> {
148 self.0.insert(key, def)
149 }
150}
151
152impl Bindings {
153 #[must_use]
155 pub fn new() -> Self {
156 Self::default()
157 }
158
159 #[must_use]
161 pub fn len(&self) -> usize {
162 self.0.len()
163 }
164
165 #[must_use]
167 pub fn is_empty(&self) -> bool {
168 self.0.is_empty()
169 }
170
171 pub fn get(&self, key: &Key) -> Option<Nullable<&TermDefinition>> {
176 self.0.get(key).map(Nullable::as_ref)
177 }
178
179 #[must_use]
181 pub fn get_entry(&self, i: usize) -> Option<(&Key, Nullable<&TermDefinition>)> {
182 self.0.get_index(i).map(|(key, value)| (key, value.as_ref()))
183 }
184
185 #[must_use]
187 pub fn iter(&self) -> BindingsIter<'_> {
188 BindingsIter(self.0.iter())
189 }
190
191 pub fn insert_with(&mut self, key: Key, def: Nullable<TermDefinition>) -> Option<Nullable<TermDefinition>> {
195 self.0.insert(key, def)
196 }
197}
198
199impl IntoIterator for Bindings {
200 type Item = (Key, Nullable<TermDefinition>);
201 type IntoIter = indexmap::map::IntoIter<Key, Nullable<TermDefinition>>;
202
203 fn into_iter(self) -> Self::IntoIter {
204 self.0.into_iter()
205 }
206}
207
208impl FromIterator<(Key, Nullable<TermDefinition>)> for Bindings {
209 fn from_iter<T: IntoIterator<Item = (Key, Nullable<TermDefinition>)>>(iter: T) -> Self {
210 let mut result = Self::new();
211
212 for (key, binding) in iter {
213 result.0.insert(key, binding);
214 }
215
216 result
217 }
218}
219
220pub enum FragmentRef<'a> {
222 Entry(EntryRef<'a>),
224
225 Key(EntryKeyRef<'a>),
227
228 Value(EntryValueRef<'a>),
230
231 TermDefinitionFragment(term_definition::FragmentRef<'a>),
233}
234
235impl<'a> FragmentRef<'a> {
236 #[must_use]
238 pub fn is_key(&self) -> bool {
239 match self {
240 Self::Key(_) => true,
241 Self::TermDefinitionFragment(f) => f.is_key(),
242 _ => false,
243 }
244 }
245
246 #[must_use]
248 pub fn is_entry(&self) -> bool {
249 match self {
250 Self::Entry(_) => true,
251 Self::TermDefinitionFragment(f) => f.is_entry(),
252 _ => false,
253 }
254 }
255
256 #[must_use]
258 pub fn is_array(&self) -> bool {
259 match self {
260 Self::TermDefinitionFragment(i) => i.is_array(),
261 _ => false,
262 }
263 }
264
265 #[must_use]
267 pub fn is_object(&self) -> bool {
268 match self {
269 Self::Value(v) => v.is_object(),
270 Self::TermDefinitionFragment(v) => v.is_object(),
271 _ => false,
272 }
273 }
274
275 #[must_use]
277 pub fn sub_items(&self) -> SubItems<'a> {
278 match self {
279 Self::Entry(e) => SubItems::Entry(Some(e.key()), Some(Box::new(e.value()))),
280 Self::Key(_) => SubItems::None,
281 Self::Value(v) => SubItems::Value(v.sub_items()),
282 Self::TermDefinitionFragment(f) => SubItems::TermDefinitionFragment(f.sub_fragments()),
283 }
284 }
285}
286
287pub enum EntryValueSubItems<'a> {
289 None,
291 TermDefinitionFragment(Box<term_definition::Entries<'a>>),
293}
294
295impl<'a> Iterator for EntryValueSubItems<'a> {
296 type Item = FragmentRef<'a>;
297
298 fn next(&mut self) -> Option<Self::Item> {
299 match self {
300 Self::None => None,
301 Self::TermDefinitionFragment(d) => d.next().map(|e| FragmentRef::TermDefinitionFragment(term_definition::FragmentRef::Entry(e))),
302 }
303 }
304}
305
306pub enum SubItems<'a> {
308 None,
310 Entry(Option<EntryKeyRef<'a>>, Option<Box<EntryValueRef<'a>>>),
312 Value(EntryValueSubItems<'a>),
314 TermDefinitionFragment(term_definition::SubFragments<'a>),
316}
317
318impl<'a> Iterator for SubItems<'a> {
319 type Item = FragmentRef<'a>;
320
321 fn next(&mut self) -> Option<Self::Item> {
322 match self {
323 Self::None => None,
324 Self::Entry(k, v) => k.take().map(FragmentRef::Key).or_else(|| v.take().map(|v| FragmentRef::Value(*v))),
325 Self::Value(d) => d.next(),
326 Self::TermDefinitionFragment(d) => d.next().map(FragmentRef::TermDefinitionFragment),
327 }
328 }
329}
330
331#[cfg(all(test, feature = "serde"))]
332#[allow(clippy::unwrap_used, clippy::expect_used)]
334mod tests {
335 use super::Definition;
336
337 #[test]
338 fn deserialize_null_vocab() {
339 let definition: Definition = jstrict::from_value(jstrict::json!({
340 "@vocab": null
341 }))
342 .unwrap();
343 assert_eq!(definition.vocab, Some(crate::Nullable::Null));
344 }
345
346 #[test]
347 fn deserialize_no_vocab() {
348 let definition: Definition = jstrict::from_value(jstrict::json!({})).unwrap();
349 assert_eq!(definition.vocab, None);
350 }
351}