jsonld_syntax/context/definition/
mod.rs1use super::{TermDefinition, term_definition};
2use crate::{Direction, Keyword, LenientLangTagBuf, Nullable, hash::IndexMap};
3use educe::Educe;
4use iri_rs::IriRefBuf;
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, Educe, Debug)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26#[educe(Default)]
27pub struct Definition {
28 #[cfg_attr(
29 feature = "serde",
30 serde(rename = "@base", default, deserialize_with = "Nullable::optional", skip_serializing_if = "Option::is_none")
31 )]
32 pub base: Option<Nullable<IriRefBuf>>,
34
35 #[cfg_attr(feature = "serde", serde(rename = "@import", default, skip_serializing_if = "Option::is_none"))]
36 pub import: Option<IriRefBuf>,
38
39 #[cfg_attr(
40 feature = "serde",
41 serde(rename = "@language", default, deserialize_with = "Nullable::optional", skip_serializing_if = "Option::is_none")
42 )]
43 pub language: Option<Nullable<LenientLangTagBuf>>,
45
46 #[cfg_attr(
47 feature = "serde",
48 serde(rename = "@direction", default, deserialize_with = "Nullable::optional", skip_serializing_if = "Option::is_none")
49 )]
50 pub direction: Option<Nullable<Direction>>,
52
53 #[cfg_attr(feature = "serde", serde(rename = "@propagate", default, skip_serializing_if = "Option::is_none"))]
54 pub propagate: Option<bool>,
56
57 #[cfg_attr(feature = "serde", serde(rename = "@protected", default, skip_serializing_if = "Option::is_none"))]
58 pub protected: Option<bool>,
60
61 #[cfg_attr(feature = "serde", serde(rename = "@type", default, skip_serializing_if = "Option::is_none"))]
62 pub type_: Option<Type>,
65
66 #[cfg_attr(feature = "serde", serde(rename = "@version", default, skip_serializing_if = "Option::is_none"))]
67 pub version: Option<Version>,
69
70 #[cfg_attr(
71 feature = "serde",
72 serde(rename = "@vocab", default, deserialize_with = "Nullable::optional", skip_serializing_if = "Option::is_none")
73 )]
74 pub vocab: Option<Nullable<Vocab>>,
76
77 #[cfg_attr(feature = "serde", serde(flatten))]
78 pub bindings: Bindings,
80}
81
82impl Definition {
83 #[must_use]
85 pub fn new() -> Self {
86 Self::default()
87 }
88
89 pub fn get(&self, key: &KeyOrKeyword) -> Option<EntryValueRef<'_>> {
94 match key {
95 KeyOrKeyword::Keyword(k) => match k {
96 Keyword::Base => self.base.as_ref().map(Nullable::as_ref).map(EntryValueRef::Base),
97 Keyword::Import => self.import.as_ref().map(EntryValueRef::Import),
98 Keyword::Language => self.language.as_ref().map(Nullable::as_ref).map(EntryValueRef::Language),
99 Keyword::Direction => self.direction.map(EntryValueRef::Direction),
100 Keyword::Propagate => self.propagate.map(EntryValueRef::Propagate),
101 Keyword::Protected => self.protected.map(EntryValueRef::Protected),
102 Keyword::Type => self.type_.map(EntryValueRef::Type),
103 Keyword::Version => self.version.map(EntryValueRef::Version),
104 Keyword::Vocab => self.vocab.as_ref().map(Nullable::as_ref).map(EntryValueRef::Vocab),
105 _ => None,
106 },
107 KeyOrKeyword::Key(k) => self.bindings.get(k).map(EntryValueRef::Definition),
108 }
109 }
110
111 #[must_use]
113 pub fn get_binding(&self, key: &Key) -> Option<Nullable<&TermDefinition>> {
114 self.bindings.get(key)
115 }
116}
117
118#[derive(PartialEq, Eq, Clone, Educe, Debug)]
120#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
121#[cfg_attr(feature = "serde", serde(transparent))]
122#[educe(Default)]
123pub struct Bindings(IndexMap<Key, Nullable<TermDefinition>>);
124
125pub struct BindingsIter<'a>(indexmap::map::Iter<'a, Key, Nullable<TermDefinition>>);
127
128impl<'a> Iterator for BindingsIter<'a> {
129 type Item = (&'a Key, Nullable<&'a TermDefinition>);
130
131 fn next(&mut self) -> Option<Self::Item> {
132 self.0.next().map(|(k, d)| (k, d.as_ref()))
133 }
134
135 fn size_hint(&self) -> (usize, Option<usize>) {
136 self.0.size_hint()
137 }
138}
139
140impl DoubleEndedIterator for BindingsIter<'_> {
141 fn next_back(&mut self) -> Option<Self::Item> {
142 self.0.next_back().map(|(k, d)| (k, d.as_ref()))
143 }
144}
145
146impl ExactSizeIterator for BindingsIter<'_> {}
147
148impl Bindings {
149 pub fn insert(&mut self, key: Key, def: Nullable<TermDefinition>) -> Option<Nullable<TermDefinition>> {
151 self.0.insert(key, def)
152 }
153}
154
155impl Bindings {
156 #[must_use]
158 pub fn new() -> Self {
159 Self::default()
160 }
161
162 #[must_use]
164 pub fn len(&self) -> usize {
165 self.0.len()
166 }
167
168 #[must_use]
170 pub fn is_empty(&self) -> bool {
171 self.0.is_empty()
172 }
173
174 pub fn get(&self, key: &Key) -> Option<Nullable<&TermDefinition>> {
179 self.0.get(key).map(Nullable::as_ref)
180 }
181
182 #[must_use]
184 pub fn get_entry(&self, i: usize) -> Option<(&Key, Nullable<&TermDefinition>)> {
185 self.0.get_index(i).map(|(key, value)| (key, value.as_ref()))
186 }
187
188 #[must_use]
190 pub fn iter(&self) -> BindingsIter<'_> {
191 BindingsIter(self.0.iter())
192 }
193
194 pub fn insert_with(&mut self, key: Key, def: Nullable<TermDefinition>) -> Option<Nullable<TermDefinition>> {
198 self.0.insert(key, def)
199 }
200}
201
202impl IntoIterator for Bindings {
203 type Item = (Key, Nullable<TermDefinition>);
204 type IntoIter = indexmap::map::IntoIter<Key, Nullable<TermDefinition>>;
205
206 fn into_iter(self) -> Self::IntoIter {
207 self.0.into_iter()
208 }
209}
210
211impl FromIterator<(Key, Nullable<TermDefinition>)> for Bindings {
212 fn from_iter<T: IntoIterator<Item = (Key, Nullable<TermDefinition>)>>(iter: T) -> Self {
213 let mut result = Self::new();
214
215 for (key, binding) in iter {
216 result.0.insert(key, binding);
217 }
218
219 result
220 }
221}
222
223pub enum FragmentRef<'a> {
225 Entry(EntryRef<'a>),
227
228 Key(EntryKeyRef<'a>),
230
231 Value(EntryValueRef<'a>),
233
234 TermDefinitionFragment(term_definition::FragmentRef<'a>),
236}
237
238impl<'a> FragmentRef<'a> {
239 #[must_use]
241 pub fn is_key(&self) -> bool {
242 match self {
243 Self::Key(_) => true,
244 Self::TermDefinitionFragment(f) => f.is_key(),
245 _ => false,
246 }
247 }
248
249 #[must_use]
251 pub fn is_entry(&self) -> bool {
252 match self {
253 Self::Entry(_) => true,
254 Self::TermDefinitionFragment(f) => f.is_entry(),
255 _ => false,
256 }
257 }
258
259 #[must_use]
261 pub fn is_array(&self) -> bool {
262 match self {
263 Self::TermDefinitionFragment(i) => i.is_array(),
264 _ => false,
265 }
266 }
267
268 #[must_use]
270 pub fn is_object(&self) -> bool {
271 match self {
272 Self::Value(v) => v.is_object(),
273 Self::TermDefinitionFragment(v) => v.is_object(),
274 _ => false,
275 }
276 }
277
278 #[must_use]
280 pub fn sub_items(&self) -> SubItems<'a> {
281 match self {
282 Self::Entry(e) => SubItems::Entry(Some(e.key()), Some(Box::new(e.value()))),
283 Self::Key(_) => SubItems::None,
284 Self::Value(v) => SubItems::Value(v.sub_items()),
285 Self::TermDefinitionFragment(f) => SubItems::TermDefinitionFragment(f.sub_fragments()),
286 }
287 }
288}
289
290pub enum EntryValueSubItems<'a> {
292 None,
294 TermDefinitionFragment(Box<term_definition::Entries<'a>>),
296}
297
298impl<'a> Iterator for EntryValueSubItems<'a> {
299 type Item = FragmentRef<'a>;
300
301 fn next(&mut self) -> Option<Self::Item> {
302 match self {
303 Self::None => None,
304 Self::TermDefinitionFragment(d) => d.next().map(|e| FragmentRef::TermDefinitionFragment(term_definition::FragmentRef::Entry(e))),
305 }
306 }
307}
308
309pub enum SubItems<'a> {
311 None,
313 Entry(Option<EntryKeyRef<'a>>, Option<Box<EntryValueRef<'a>>>),
315 Value(EntryValueSubItems<'a>),
317 TermDefinitionFragment(term_definition::SubFragments<'a>),
319}
320
321impl<'a> Iterator for SubItems<'a> {
322 type Item = FragmentRef<'a>;
323
324 fn next(&mut self) -> Option<Self::Item> {
325 match self {
326 Self::None => None,
327 Self::Entry(k, v) => k.take().map(FragmentRef::Key).or_else(|| v.take().map(|v| FragmentRef::Value(*v))),
328 Self::Value(d) => d.next(),
329 Self::TermDefinitionFragment(d) => d.next().map(FragmentRef::TermDefinitionFragment),
330 }
331 }
332}
333
334#[cfg(all(test, feature = "serde"))]
335#[allow(clippy::unwrap_used, clippy::expect_used)]
337mod tests {
338 use super::Definition;
339
340 #[test]
341 fn deserialize_null_vocab() {
342 let definition: Definition = jstrict::from_value(jstrict::json!({
343 "@vocab": null
344 }))
345 .unwrap();
346 assert_eq!(definition.vocab, Some(crate::Nullable::Null));
347 }
348
349 #[test]
350 fn deserialize_no_vocab() {
351 let definition: Definition = jstrict::from_value(jstrict::json!({})).unwrap();
352 assert_eq!(definition.vocab, None);
353 }
354}