knowledge_base_extension_framework/
registry.rs1use crate::bindings::{BindingValue, ResolvedBindings};
2use crate::contracts::{BindingKind, BindingReference, ExtensionId, ExtensionMetadata, KnowledgeBaseExtension};
3use crate::error::FrameworkError;
4use knowledge_base_validation::KnowledgeBaseValidator;
5use std::collections::{BTreeMap, BTreeSet};
6use std::sync::Arc;
7
8pub struct ExtensionRegistry {
10 extensions: BTreeMap<ExtensionId, Arc<dyn KnowledgeBaseExtension>>,
11}
12
13impl ExtensionRegistry {
14 pub fn new(extensions: impl IntoIterator<Item = Arc<dyn KnowledgeBaseExtension>>) -> Result<Self, FrameworkError> {
16 let mut registered = BTreeMap::new();
17 for extension in extensions {
18 let metadata = extension.metadata();
19 validate_metadata(metadata)?;
20 let id = metadata.id.clone();
21 if registered.insert(id.clone(), extension).is_some() {
22 return Err(FrameworkError::DuplicateExtension(id));
23 }
24 }
25
26 let registry = Self { extensions: registered };
27 for extension in registry.extensions.values() {
28 registry.validate_dependencies(extension.metadata())?;
29 registry.validate_requirements(extension.metadata())?;
30 }
31 Ok(registry)
32 }
33
34 pub fn resolve_active(&self, requested: impl IntoIterator<Item = ExtensionId>) -> Result<ActiveExtensions, FrameworkError> {
36 let requested = requested.into_iter().collect::<BTreeSet<_>>();
37 let mut ordered = Vec::new();
38 let mut state = BTreeMap::new();
39 for id in &requested {
40 self.visit(id, &requested, &mut state, &mut ordered, &mut Vec::new())?;
41 }
42 Ok(ActiveExtensions { ordered })
43 }
44
45 pub fn metadata(&self, id: &ExtensionId) -> Option<&ExtensionMetadata> {
47 self.extensions.get(id).map(|extension| extension.metadata())
48 }
49
50 pub fn extensions(&self) -> impl Iterator<Item = &dyn KnowledgeBaseExtension> {
52 self.extensions.values().map(AsRef::as_ref)
53 }
54
55 fn validate_dependencies(&self, metadata: &ExtensionMetadata) -> Result<(), FrameworkError> {
56 for dependency in &metadata.dependencies {
57 let available = self.extensions.get(&dependency.id).ok_or_else(|| FrameworkError::MissingDependency {
58 extension: metadata.id.clone(),
59 dependency: dependency.id.clone(),
60 })?;
61 if available.metadata().contract != dependency.contract {
62 return Err(FrameworkError::UnsupportedContract {
63 extension: metadata.id.clone(),
64 required: dependency.contract,
65 available: available.metadata().contract,
66 });
67 }
68 }
69 Ok(())
70 }
71
72 fn validate_requirements(&self, metadata: &ExtensionMetadata) -> Result<(), FrameworkError> {
73 for requirement in &metadata.ontology_requirements.entity_types {
74 self.validate_requirement_binding(metadata, &requirement.binding, BindingKind::EntityType)?;
75 }
76 for requirement in &metadata.ontology_requirements.properties {
77 self.validate_requirement_binding(metadata, &requirement.binding, BindingKind::Property)?;
78 for binding in &requirement.subject_types {
79 self.validate_requirement_binding(metadata, binding, BindingKind::EntityType)?;
80 }
81 if let Some(target_types) = &requirement.target_types {
82 for binding in target_types {
83 self.validate_requirement_binding(metadata, binding, BindingKind::EntityType)?;
84 }
85 }
86 for binding in &requirement.allowed_qualifiers {
87 self.validate_requirement_binding(metadata, binding, BindingKind::Property)?;
88 }
89 }
90 Ok(())
91 }
92
93 fn validate_requirement_binding(&self, metadata: &ExtensionMetadata, reference: &BindingReference, expected: BindingKind) -> Result<(), FrameworkError> {
94 if reference.extension_id() != &metadata.id && !metadata.dependencies.iter().any(|dependency| dependency.id == *reference.extension_id()) {
95 return Err(FrameworkError::InaccessibleBinding {
96 extension: metadata.id.clone(),
97 binding: reference.clone(),
98 });
99 }
100 let owner = self.extensions.get(reference.extension_id()).expect("dependency availability was validated").metadata();
101 let declaration = owner
102 .bindings
103 .iter()
104 .find(|binding| binding.key == *reference.key())
105 .ok_or_else(|| FrameworkError::UndeclaredBinding {
106 extension: owner.id.clone(),
107 binding: reference.clone(),
108 })?;
109 if declaration.kind != expected {
110 return Err(FrameworkError::InvalidRequirement {
111 extension: metadata.id.clone(),
112 binding: reference.clone(),
113 expected,
114 });
115 }
116 Ok(())
117 }
118
119 fn visit(
121 &self,
122 id: &ExtensionId,
123 requested: &BTreeSet<ExtensionId>,
124 state: &mut BTreeMap<ExtensionId, Visit>,
125 ordered: &mut Vec<Arc<dyn KnowledgeBaseExtension>>,
126 stack: &mut Vec<ExtensionId>,
127 ) -> Result<(), FrameworkError> {
128 match state.get(id) {
129 Some(Visit::Done) => return Ok(()),
130 Some(Visit::Visiting) => {
131 let start = stack.iter().position(|item| item == id).expect("visiting extension is on stack");
132 let mut cycle = stack[start..].to_vec();
133 cycle.push(id.clone());
134 return Err(FrameworkError::DependencyCycle(cycle));
135 }
136 None => {}
137 }
138 let extension = self
139 .extensions
140 .get(id)
141 .ok_or_else(|| FrameworkError::MissingDependency {
142 extension: id.clone(),
143 dependency: id.clone(),
144 })?
145 .clone();
146 state.insert(id.clone(), Visit::Visiting);
147 stack.push(id.clone());
148 for dependency in &extension.metadata().dependencies {
149 if !requested.contains(&dependency.id) {
150 return Err(FrameworkError::InactiveDependency {
151 extension: id.clone(),
152 dependency: dependency.id.clone(),
153 });
154 }
155 self.visit(&dependency.id, requested, state, ordered, stack)?;
156 }
157 stack.pop();
158 state.insert(id.clone(), Visit::Done);
159 ordered.push(extension);
160 Ok(())
161 }
162}
163
164#[derive(Clone, Copy)]
165enum Visit {
166 Visiting,
167 Done,
168}
169
170pub struct ActiveExtensions {
172 ordered: Vec<Arc<dyn KnowledgeBaseExtension>>,
173}
174
175impl ActiveExtensions {
176 pub fn extensions(&self) -> &[Arc<dyn KnowledgeBaseExtension>] {
177 &self.ordered
178 }
179
180 pub fn validators(&self, bindings: &ResolvedBindings) -> Result<Vec<Arc<dyn KnowledgeBaseValidator>>, FrameworkError> {
182 let mut validators = Vec::new();
183 for extension in &self.ordered {
184 validators.extend(extension.validators(bindings)?);
185 }
186 Ok(validators)
187 }
188
189 pub fn resolve_bindings(&self, declared: BTreeMap<BindingReference, BindingValue>) -> Result<ResolvedBindings, FrameworkError> {
191 let metadata = self
192 .ordered
193 .iter()
194 .map(|extension| (extension.metadata().id.clone(), extension.metadata()))
195 .collect::<BTreeMap<_, _>>();
196 let mut resolved = ResolvedBindings::default();
197 for (reference, value) in declared {
198 let owner = metadata.get(reference.extension_id()).ok_or_else(|| FrameworkError::MissingBinding(reference.clone()))?;
199 let declaration = owner
200 .bindings
201 .iter()
202 .find(|item| item.key == *reference.key())
203 .ok_or_else(|| FrameworkError::UndeclaredBinding {
204 extension: owner.id.clone(),
205 binding: reference.clone(),
206 })?;
207 if declaration.kind != value.kind() {
208 return Err(FrameworkError::BindingKindMismatch {
209 binding: reference,
210 expected: declaration.kind,
211 actual: value.kind(),
212 });
213 }
214 resolved.values.insert(reference, value);
215 }
216 for extension in &self.ordered {
217 for declaration in &extension.metadata().bindings {
218 let reference = BindingReference::new(extension.metadata().id.clone(), declaration.key.clone());
219 if !resolved.values.contains_key(&reference) {
220 return Err(FrameworkError::MissingBinding(reference));
221 }
222 }
223 }
224 Ok(resolved)
225 }
226}
227
228fn validate_metadata(metadata: &ExtensionMetadata) -> Result<(), FrameworkError> {
229 let mut dependencies = BTreeSet::new();
230 for dependency in &metadata.dependencies {
231 if !dependencies.insert(dependency.id.clone()) {
232 return Err(FrameworkError::DuplicateDependency {
233 extension: metadata.id.clone(),
234 dependency: dependency.id.clone(),
235 });
236 }
237 }
238 let mut bindings = BTreeMap::new();
239 for binding in &metadata.bindings {
240 if bindings.insert(binding.key.clone(), binding.kind).is_some() {
241 return Err(FrameworkError::DuplicateBinding {
242 extension: metadata.id.clone(),
243 key: binding.key.clone(),
244 });
245 }
246 }
247 Ok(())
248}