jsonld_syntax/context/definition/
mod.rs1use super::{TermDefinition, term_definition};
2use crate::{Direction, Keyword, LenientLangTagBuf, Nullable, hash::IndexMap};
3use iri_rs::IriRefBuf;
4use std::{borrow::Borrow, hash::Hash};
5
6mod import;
7mod key;
8mod reference;
9mod type_;
10mod version;
11mod vocab;
12
13pub use import::*;
14pub use key::*;
15pub use reference::*;
16pub use type_::*;
17pub use version::*;
18pub use vocab::*;
19
20#[derive(PartialEq, Eq, Clone, Default, Debug)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26pub struct Definition {
27 #[cfg_attr(
28 feature = "serde",
29 serde(rename = "@base", default, deserialize_with = "Nullable::optional", skip_serializing_if = "Option::is_none")
30 )]
31 pub base: Option<Nullable<IriRefBuf>>,
33
34 #[cfg_attr(feature = "serde", serde(rename = "@import", default, skip_serializing_if = "Option::is_none"))]
35 pub import: Option<IriRefBuf>,
37
38 #[cfg_attr(
39 feature = "serde",
40 serde(rename = "@language", default, deserialize_with = "Nullable::optional", skip_serializing_if = "Option::is_none")
41 )]
42 pub language: Option<Nullable<LenientLangTagBuf>>,
44
45 #[cfg_attr(
46 feature = "serde",
47 serde(rename = "@direction", default, deserialize_with = "Nullable::optional", skip_serializing_if = "Option::is_none")
48 )]
49 pub direction: Option<Nullable<Direction>>,
51
52 #[cfg_attr(feature = "serde", serde(rename = "@propagate", default, skip_serializing_if = "Option::is_none"))]
53 pub propagate: Option<bool>,
55
56 #[cfg_attr(feature = "serde", serde(rename = "@protected", default, skip_serializing_if = "Option::is_none"))]
57 pub protected: Option<bool>,
59
60 #[cfg_attr(feature = "serde", serde(rename = "@type", default, skip_serializing_if = "Option::is_none"))]
61 pub type_: Option<Type>,
64
65 #[cfg_attr(feature = "serde", serde(rename = "@version", default, skip_serializing_if = "Option::is_none"))]
66 pub version: Option<Version>,
68
69 #[cfg_attr(
70 feature = "serde",
71 serde(rename = "@vocab", default, deserialize_with = "Nullable::optional", skip_serializing_if = "Option::is_none")
72 )]
73 pub vocab: Option<Nullable<Vocab>>,
75
76 #[cfg_attr(feature = "serde", serde(flatten))]
77 pub bindings: Bindings,
79}
80
81impl Definition {
82 #[must_use]
84 pub fn new() -> Self {
85 Self::default()
86 }
87
88 pub fn get(&self, key: &KeyOrKeyword) -> Option<EntryValueRef<'_>> {
93 match key {
94 KeyOrKeyword::Keyword(k) => match k {
95 Keyword::Base => self.base.as_ref().map(Nullable::as_ref).map(EntryValueRef::Base),
96 Keyword::Import => self.import.as_ref().map(EntryValueRef::Import),
97 Keyword::Language => self.language.as_ref().map(Nullable::as_ref).map(EntryValueRef::Language),
98 Keyword::Direction => self.direction.map(EntryValueRef::Direction),
99 Keyword::Propagate => self.propagate.map(EntryValueRef::Propagate),
100 Keyword::Protected => self.protected.map(EntryValueRef::Protected),
101 Keyword::Type => self.type_.map(EntryValueRef::Type),
102 Keyword::Version => self.version.map(EntryValueRef::Version),
103 Keyword::Vocab => self.vocab.as_ref().map(Nullable::as_ref).map(EntryValueRef::Vocab),
104 _ => None,
105 },
106 KeyOrKeyword::Key(k) => self.bindings.get(k).map(EntryValueRef::Definition),
107 }
108 }
109
110 #[must_use]
112 pub fn get_binding<Q>(&self, key: &Q) -> Option<Nullable<&TermDefinition>>
113 where
114 Q: ?Sized + Hash + Eq,
115 Key: Borrow<Q>,
116 {
117 self.bindings.get(key)
118 }
119}
120
121#[derive(PartialEq, Eq, Clone, Default, Debug)]
123#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
124#[cfg_attr(feature = "serde", serde(transparent))]
125pub struct Bindings(IndexMap<Key, Nullable<TermDefinition>>);
126
127pub struct BindingsIter<'a>(indexmap::map::Iter<'a, Key, Nullable<TermDefinition>>);
129
130impl<'a> Iterator for BindingsIter<'a> {
131 type Item = (&'a Key, Nullable<&'a TermDefinition>);
132
133 fn next(&mut self) -> Option<Self::Item> {
134 self.0.next().map(|(k, d)| (k, d.as_ref()))
135 }
136
137 fn size_hint(&self) -> (usize, Option<usize>) {
138 self.0.size_hint()
139 }
140}
141
142impl DoubleEndedIterator for BindingsIter<'_> {
143 fn next_back(&mut self) -> Option<Self::Item> {
144 self.0.next_back().map(|(k, d)| (k, d.as_ref()))
145 }
146}
147
148impl ExactSizeIterator for BindingsIter<'_> {}
149
150impl Bindings {
151 pub fn insert(&mut self, key: Key, def: Nullable<TermDefinition>) -> Option<Nullable<TermDefinition>> {
153 self.0.insert(key, def)
154 }
155}
156
157impl Bindings {
158 #[must_use]
160 pub fn new() -> Self {
161 Self::default()
162 }
163
164 #[must_use]
166 pub fn len(&self) -> usize {
167 self.0.len()
168 }
169
170 #[must_use]
172 pub fn is_empty(&self) -> bool {
173 self.0.is_empty()
174 }
175
176 pub fn get<Q>(&self, key: &Q) -> Option<Nullable<&TermDefinition>>
181 where
182 Q: ?Sized + Hash + Eq,
183 Key: Borrow<Q>,
184 {
185 self.0.get(key).map(Nullable::as_ref)
186 }
187
188 pub fn get_key<Q>(&self, key: &Q) -> Option<&Key>
193 where
194 Q: ?Sized + Hash + Eq,
195 Key: Borrow<Q>,
196 {
197 self.0.get_key_value(key).map(|(key, _)| key)
198 }
199
200 #[must_use]
202 pub fn get_entry(&self, i: usize) -> Option<(&Key, Nullable<&TermDefinition>)> {
203 self.0.get_index(i).map(|(key, value)| (key, value.as_ref()))
204 }
205
206 #[must_use]
208 pub fn iter(&self) -> BindingsIter<'_> {
209 BindingsIter(self.0.iter())
210 }
211
212 pub fn insert_with(&mut self, key: Key, def: Nullable<TermDefinition>) -> Option<Nullable<TermDefinition>> {
216 self.0.insert(key, def)
217 }
218}
219
220impl IntoIterator for Bindings {
221 type Item = (Key, Nullable<TermDefinition>);
222 type IntoIter = indexmap::map::IntoIter<Key, Nullable<TermDefinition>>;
223
224 fn into_iter(self) -> Self::IntoIter {
225 self.0.into_iter()
226 }
227}
228
229impl FromIterator<(Key, Nullable<TermDefinition>)> for Bindings {
230 fn from_iter<T: IntoIterator<Item = (Key, Nullable<TermDefinition>)>>(iter: T) -> Self {
231 let mut result = Self::new();
232
233 for (key, binding) in iter {
234 result.0.insert(key, binding);
235 }
236
237 result
238 }
239}
240
241pub enum FragmentRef<'a> {
243 Entry(EntryRef<'a>),
245
246 Key(EntryKeyRef<'a>),
248
249 Value(EntryValueRef<'a>),
251
252 TermDefinitionFragment(term_definition::FragmentRef<'a>),
254}
255
256impl<'a> FragmentRef<'a> {
257 #[must_use]
259 pub fn is_key(&self) -> bool {
260 match self {
261 Self::Key(_) => true,
262 Self::TermDefinitionFragment(f) => f.is_key(),
263 _ => false,
264 }
265 }
266
267 #[must_use]
269 pub fn is_entry(&self) -> bool {
270 match self {
271 Self::Entry(_) => true,
272 Self::TermDefinitionFragment(f) => f.is_entry(),
273 _ => false,
274 }
275 }
276
277 #[must_use]
279 pub fn is_array(&self) -> bool {
280 match self {
281 Self::TermDefinitionFragment(i) => i.is_array(),
282 _ => false,
283 }
284 }
285
286 #[must_use]
288 pub fn is_object(&self) -> bool {
289 match self {
290 Self::Value(v) => v.is_object(),
291 Self::TermDefinitionFragment(v) => v.is_object(),
292 _ => false,
293 }
294 }
295
296 #[must_use]
298 pub fn sub_items(&self) -> SubItems<'a> {
299 match self {
300 Self::Entry(e) => SubItems::Entry(Some(e.key()), Some(Box::new(e.value()))),
301 Self::Key(_) => SubItems::None,
302 Self::Value(v) => SubItems::Value(v.sub_items()),
303 Self::TermDefinitionFragment(f) => SubItems::TermDefinitionFragment(f.sub_fragments()),
304 }
305 }
306}
307
308pub enum EntryValueSubItems<'a> {
310 None,
312 TermDefinitionFragment(Box<term_definition::Entries<'a>>),
314}
315
316impl<'a> Iterator for EntryValueSubItems<'a> {
317 type Item = FragmentRef<'a>;
318
319 fn next(&mut self) -> Option<Self::Item> {
320 match self {
321 Self::None => None,
322 Self::TermDefinitionFragment(d) => d.next().map(|e| FragmentRef::TermDefinitionFragment(term_definition::FragmentRef::Entry(e))),
323 }
324 }
325}
326
327pub enum SubItems<'a> {
329 None,
331 Entry(Option<EntryKeyRef<'a>>, Option<Box<EntryValueRef<'a>>>),
333 Value(EntryValueSubItems<'a>),
335 TermDefinitionFragment(term_definition::SubFragments<'a>),
337}
338
339impl<'a> Iterator for SubItems<'a> {
340 type Item = FragmentRef<'a>;
341
342 fn next(&mut self) -> Option<Self::Item> {
343 match self {
344 Self::None => None,
345 Self::Entry(k, v) => k.take().map(FragmentRef::Key).or_else(|| v.take().map(|v| FragmentRef::Value(*v))),
346 Self::Value(d) => d.next(),
347 Self::TermDefinitionFragment(d) => d.next().map(FragmentRef::TermDefinitionFragment),
348 }
349 }
350}
351
352#[cfg(all(test, feature = "serde"))]
353#[allow(clippy::unwrap_used, clippy::expect_used)]
355mod tests {
356 use super::Definition;
357
358 #[test]
359 fn deserialize_null_vocab() {
360 let definition: Definition = jstrict::from_value(jstrict::json!({
361 "@vocab": null
362 }))
363 .unwrap();
364 assert_eq!(definition.vocab, Some(crate::Nullable::Null));
365 }
366
367 #[test]
368 fn deserialize_no_vocab() {
369 let definition: Definition = jstrict::from_value(jstrict::json!({})).unwrap();
370 assert_eq!(definition.vocab, None);
371 }
372}