jsonld_context_processing/algorithm/
merged.rs1use iri_rs::IriRefBuf;
2use jsonld_syntax as syntax;
3use syntax::Nullable;
4
5pub struct Merged<'a> {
15 base: &'a syntax::context::Definition,
16 imported: Option<syntax::context::Context>,
17}
18
19impl<'a> Merged<'a> {
20 #[must_use]
25 pub fn new(base: &'a syntax::context::Definition, imported: Option<syntax::context::Context>) -> Self {
26 Self { base, imported }
27 }
28
29 #[must_use]
35 pub fn imported(&self) -> Option<&syntax::context::Definition> {
36 self.imported.as_ref().and_then(|imported| match imported {
37 syntax::context::Context::One(syntax::ContextEntry::Definition(import_context)) => Some(import_context),
38 _ => None,
39 })
40 }
41
42 pub fn base(&self) -> Option<syntax::Nullable<&IriRefBuf>> {
44 self.base
45 .base
46 .as_ref()
47 .or_else(|| self.imported().and_then(|i| i.base.as_ref()))
48 .map(Nullable::as_ref)
49 }
50
51 pub fn vocab(&self) -> Option<syntax::Nullable<&syntax::context::definition::Vocab>> {
53 self.base
54 .vocab
55 .as_ref()
56 .or_else(|| self.imported().and_then(|i| i.vocab.as_ref()))
57 .map(Nullable::as_ref)
58 }
59
60 pub fn language(&self) -> Option<syntax::Nullable<&syntax::LenientLangTagBuf>> {
62 self.base
63 .language
64 .as_ref()
65 .or_else(|| self.imported().and_then(|i| i.language.as_ref()))
66 .map(Nullable::as_ref)
67 }
68
69 #[must_use]
72 pub fn direction(&self) -> Option<syntax::Nullable<syntax::Direction>> {
73 self.base.direction.or_else(|| self.imported().and_then(|i| i.direction))
74 }
75
76 #[must_use]
82 pub fn protected(&self) -> Option<bool> {
83 self.base.protected.or_else(|| self.imported().and_then(|i| i.protected))
84 }
85
86 #[must_use]
91 pub fn type_(&self) -> Option<syntax::context::definition::Type> {
92 self.base.type_.or_else(|| self.imported().and_then(|i| i.type_))
93 }
94
95 #[must_use]
98 pub fn bindings(&self) -> MergedBindings<'_> {
99 MergedBindings {
100 base: self.base,
101 base_bindings: self.base.bindings.iter(),
102 imported_bindings: self.imported().map(|i| i.bindings.iter()),
103 }
104 }
105
106 #[must_use]
108 pub fn get(&self, key: &syntax::context::definition::KeyOrKeyword) -> Option<syntax::context::definition::EntryValueRef<'_>> {
109 self.base.get(key).or_else(|| self.imported().and_then(|i| i.get(key)))
110 }
111}
112
113impl<'a> From<&'a syntax::context::Definition> for Merged<'a> {
114 fn from(base: &'a syntax::context::Definition) -> Self {
115 Self { base, imported: None }
116 }
117}
118
119type BindingRef<'a> = (&'a syntax::context::definition::Key, Nullable<&'a syntax::context::TermDefinition>);
120
121pub struct MergedBindings<'a> {
127 base: &'a syntax::context::Definition,
128 base_bindings: syntax::context::definition::BindingsIter<'a>,
129 imported_bindings: Option<syntax::context::definition::BindingsIter<'a>>,
130}
131
132impl<'a> Iterator for MergedBindings<'a> {
133 type Item = BindingRef<'a>;
134
135 fn next(&mut self) -> Option<Self::Item> {
136 match &mut self.imported_bindings {
137 Some(imported_bindings) => {
138 for (key_ref, def) in imported_bindings {
139 let key = key_ref.to_owned();
140 if self.base.get_binding(&key).is_none() {
141 return Some((key_ref, def));
142 }
143 }
144
145 self.base_bindings.next()
146 }
147 None => self.base_bindings.next(),
148 }
149 }
150}