jsonld_context_processing/algorithm/
merged.rs1use iri_rs::IriRefBuf;
2use jsonld_syntax as syntax;
3use syntax::{
4 Nullable,
5 context::definition::{KeyOrKeyword, KeyOrKeywordRef},
6};
7
8pub struct Merged<'a> {
18 base: &'a syntax::context::Definition,
19 imported: Option<syntax::context::Context>,
20}
21
22impl<'a> Merged<'a> {
23 #[must_use]
28 pub fn new(base: &'a syntax::context::Definition, imported: Option<syntax::context::Context>) -> Self {
29 Self { base, imported }
30 }
31
32 #[must_use]
38 pub fn imported(&self) -> Option<&syntax::context::Definition> {
39 self.imported.as_ref().and_then(|imported| match imported {
40 syntax::context::Context::One(syntax::ContextEntry::Definition(import_context)) => Some(import_context),
41 _ => None,
42 })
43 }
44
45 pub fn base(&self) -> Option<syntax::Nullable<&IriRefBuf>> {
47 self.base
48 .base
49 .as_ref()
50 .or_else(|| self.imported().and_then(|i| i.base.as_ref()))
51 .map(Nullable::as_ref)
52 }
53
54 pub fn vocab(&self) -> Option<syntax::Nullable<&syntax::context::definition::Vocab>> {
56 self.base
57 .vocab
58 .as_ref()
59 .or_else(|| self.imported().and_then(|i| i.vocab.as_ref()))
60 .map(Nullable::as_ref)
61 }
62
63 pub fn language(&self) -> Option<syntax::Nullable<&syntax::LenientLangTagBuf>> {
65 self.base
66 .language
67 .as_ref()
68 .or_else(|| self.imported().and_then(|i| i.language.as_ref()))
69 .map(Nullable::as_ref)
70 }
71
72 #[must_use]
75 pub fn direction(&self) -> Option<syntax::Nullable<syntax::Direction>> {
76 self.base.direction.or_else(|| self.imported().and_then(|i| i.direction))
77 }
78
79 #[must_use]
85 pub fn protected(&self) -> Option<bool> {
86 self.base.protected.or_else(|| self.imported().and_then(|i| i.protected))
87 }
88
89 #[must_use]
94 pub fn type_(&self) -> Option<syntax::context::definition::Type> {
95 self.base.type_.or_else(|| self.imported().and_then(|i| i.type_))
96 }
97
98 #[must_use]
101 pub fn bindings(&self) -> MergedBindings<'_> {
102 MergedBindings {
103 base: self.base,
104 base_bindings: self.base.bindings.iter(),
105 imported_bindings: self.imported().map(|i| i.bindings.iter()),
106 }
107 }
108
109 #[must_use]
111 pub fn get(&self, key: &syntax::context::definition::KeyOrKeyword) -> Option<syntax::context::definition::EntryValueRef<'_>> {
112 self.base.get(key).or_else(|| self.imported().and_then(|i| i.get(key)))
113 }
114
115 #[must_use]
123 pub fn bound_key(&self, term: KeyOrKeywordRef<'_>) -> Option<KeyOrKeyword> {
124 match term {
125 KeyOrKeywordRef::Keyword(keyword) => Some(KeyOrKeyword::Keyword(keyword)),
126 KeyOrKeywordRef::Key(key) => self
127 .base
128 .bindings
129 .get_key(key.as_str())
130 .or_else(|| self.imported().and_then(|i| i.bindings.get_key(key.as_str())))
131 .cloned()
132 .map(KeyOrKeyword::Key),
133 }
134 }
135}
136
137impl<'a> From<&'a syntax::context::Definition> for Merged<'a> {
138 fn from(base: &'a syntax::context::Definition) -> Self {
139 Self { base, imported: None }
140 }
141}
142
143type BindingRef<'a> = (&'a syntax::context::definition::Key, Nullable<&'a syntax::context::TermDefinition>);
144
145pub struct MergedBindings<'a> {
151 base: &'a syntax::context::Definition,
152 base_bindings: syntax::context::definition::BindingsIter<'a>,
153 imported_bindings: Option<syntax::context::definition::BindingsIter<'a>>,
154}
155
156impl<'a> Iterator for MergedBindings<'a> {
157 type Item = BindingRef<'a>;
158
159 fn next(&mut self) -> Option<Self::Item> {
160 match &mut self.imported_bindings {
161 Some(imported_bindings) => {
162 for (key_ref, def) in imported_bindings {
163 if self.base.get_binding(key_ref.as_str()).is_none() {
164 return Some((key_ref, def));
165 }
166 }
167
168 self.base_bindings.next()
169 }
170 None => self.base_bindings.next(),
171 }
172 }
173}