1use crate::{
16 ComponentDependencyKey, Expr, FullyQualifiedInterfaceName, FunctionDictionary, FunctionName,
17 FunctionType, FunctionTypeRegistry, InstanceCreationType, InterfaceName, PackageName,
18 TypeParameter,
19};
20use golem_wasm_ast::analysis::TypeEnum;
21use golem_wasm_ast::analysis::{AnalysedExport, TypeVariant};
22use std::collections::BTreeMap;
23
24#[derive(Debug, Default, Hash, Clone, Eq, PartialEq, PartialOrd, Ord)]
25pub struct ComponentDependencies {
26 pub dependencies: BTreeMap<ComponentDependencyKey, FunctionDictionary>,
27}
28
29impl ComponentDependencies {
30 pub fn get_variants(&self) -> Vec<TypeVariant> {
31 let mut variants = vec![];
32
33 for function_dict in self.dependencies.values() {
34 variants.extend(function_dict.get_all_variants());
35 }
36
37 variants
38 }
39
40 pub fn get_enums(&self) -> Vec<TypeEnum> {
41 let mut enums = vec![];
42
43 for function_dict in self.dependencies.values() {
44 enums.extend(function_dict.get_all_enums());
45 }
46
47 enums
48 }
49
50 pub fn get_function_type(
51 &self,
52 component_info: &Option<ComponentDependencyKey>,
53 function_name: &FunctionName,
54 ) -> Result<(ComponentDependencyKey, FunctionType), String> {
55 match component_info {
58 None => {
59 let mut function_types_in_component = vec![];
60
61 for (component_dependency_key, function_dict) in &self.dependencies {
62 let types = function_dict
63 .name_and_types
64 .iter()
65 .filter_map(|(f_name, function_type)| {
66 if f_name == function_name {
67 Some(function_type)
68 } else {
69 None
70 }
71 })
72 .collect::<Vec<_>>();
73
74 function_types_in_component.push((component_dependency_key.clone(), types));
75 }
76
77 if function_types_in_component.is_empty() {
78 Err("unknown function".to_string())
79 } else if function_types_in_component.len() > 1 {
80 Err(format!(
81 "function `{function_name}` is ambiguous across components"
82 ))
83 } else {
84 let (key, types) = function_types_in_component.pop().unwrap();
85
86 if types.is_empty() {
87 Err("unknown function".to_string())
88 } else {
89 Ok((key, types[0].clone()))
90 }
91 }
92 }
93 Some(component_dep_key) => {
94 let function_dictionary = self
95 .dependencies
96 .get(component_dep_key)
97 .cloned()
98 .ok_or_else(|| {
99 format!(
100 "component dependency for `{}` not found",
101 component_dep_key.component_name
102 )
103 })?;
104
105 let function_type = function_dictionary.name_and_types.iter().find_map(
106 |(f_name, function_type)| {
107 if f_name == function_name {
108 Some(function_type.clone())
109 } else {
110 None
111 }
112 },
113 );
114
115 if let Some(function_type) = function_type {
116 Ok((component_dep_key.clone(), function_type))
117 } else {
118 Err(format!(
119 "function `{}` not found in component `{}`",
120 function_name, component_dep_key.component_name
121 ))
122 }
123 }
124 }
125 }
126
127 pub fn narrow_to_component(&mut self, component_dependency_key: &ComponentDependencyKey) {
128 if let Some(function_dict) = self.dependencies.remove(component_dependency_key) {
130 self.dependencies.clear();
131 self.dependencies
132 .insert(component_dependency_key.clone(), function_dict);
133 }
134 }
135
136 pub fn function_dictionary(&self) -> Vec<&FunctionDictionary> {
137 self.dependencies.values().collect::<Vec<_>>()
138 }
139
140 pub fn filter_by_interface(
141 &self,
142 interface_name: &InterfaceName,
143 ) -> Result<crate::ComponentDependencies, String> {
144 let mut tree = BTreeMap::new();
145
146 for (component_info, function_dict) in self.dependencies.iter() {
147 let name_and_types: Vec<&(FunctionName, FunctionType)> = function_dict
148 .name_and_types
149 .iter()
150 .filter(|(f, _)| f.interface_name().as_ref() == Some(interface_name))
151 .collect::<Vec<_>>();
152
153 if !name_and_types.is_empty() {
154 tree.insert(
155 component_info.clone(),
156 FunctionDictionary {
157 name_and_types: name_and_types.into_iter().cloned().collect(),
158 },
159 );
160 }
161 }
162
163 if tree.is_empty() {
164 return Err(format!("interface `{interface_name}` not found"));
165 }
166
167 Ok(ComponentDependencies { dependencies: tree })
168 }
169
170 pub fn filter_by_package_name(
171 &self,
172 package_name: &PackageName,
173 ) -> Result<crate::ComponentDependencies, String> {
174 let mut tree = BTreeMap::new();
176
177 for (component_info, function_dict) in self.dependencies.iter() {
178 if let Some(root_package_name) = &component_info.root_package_name {
179 if root_package_name == &package_name.to_string() {
180 tree.insert(component_info.clone(), function_dict.clone());
181 }
182 } else {
183 let name_and_types = function_dict
186 .name_and_types
187 .iter()
188 .filter(|(f, _)| f.package_name() == Some(package_name.clone()))
189 .collect::<Vec<_>>();
190
191 if !name_and_types.is_empty() {
192 tree.insert(
193 component_info.clone(),
194 FunctionDictionary {
195 name_and_types: name_and_types.into_iter().cloned().collect(),
196 },
197 );
198 }
199 }
200 }
201
202 if tree.is_empty() {
203 return Err(format!("package `{package_name}` not found"));
204 }
205
206 Ok(crate::ComponentDependencies { dependencies: tree })
207 }
208
209 pub fn filter_by_fully_qualified_interface(
210 &self,
211 fqi: &FullyQualifiedInterfaceName,
212 ) -> Result<Self, String> {
213 let mut tree = BTreeMap::new();
214
215 for (component_info, function_dict) in self.dependencies.iter() {
216 if let Some(root_package_name) = &component_info.root_package_name {
217 if root_package_name == &fqi.package_name.to_string() {
218 tree.insert(component_info.clone(), function_dict.clone());
219 }
220 } else {
221 let name_and_types = function_dict
224 .name_and_types
225 .iter()
226 .filter(|(f, _)| {
227 f.package_name() == Some(fqi.package_name.clone())
228 && f.interface_name() == Some(fqi.interface_name.clone())
229 })
230 .collect::<Vec<_>>();
231
232 if !name_and_types.is_empty() {
233 tree.insert(
234 component_info.clone(),
235 FunctionDictionary {
236 name_and_types: name_and_types.into_iter().cloned().collect(),
237 },
238 );
239 }
240 }
241 }
242
243 if tree.is_empty() {
244 return Err(format!("`{fqi}` not found"));
245 }
246
247 Ok(ComponentDependencies { dependencies: tree })
248 }
249
250 pub fn get_worker_instance_type(
254 &self,
255 type_parameter: Option<TypeParameter>,
256 worker_name: Option<Expr>,
257 ) -> Result<InstanceCreationType, String> {
258 match type_parameter {
259 None => Ok(InstanceCreationType::WitWorker {
260 component_info: None,
261 worker_name: worker_name.map(Box::new),
262 }),
263
264 Some(TypeParameter::PackageName(package_name)) => {
265 let result = self
267 .dependencies
268 .iter()
269 .find(|(x, _)| match &x.root_package_name {
270 Some(name) => {
271 let pkg = match &x.root_package_version {
272 None => name.to_string(),
273 Some(version) => format!("{name}@{version}"),
274 };
275
276 pkg == package_name.to_string()
277 }
278
279 None => false,
280 });
281
282 if let Some(result) = result {
283 Ok(InstanceCreationType::WitWorker {
284 component_info: Some(result.0.clone()),
285 worker_name: worker_name.map(Box::new),
286 })
287 } else {
288 Ok(InstanceCreationType::WitWorker {
289 component_info: None,
290 worker_name: worker_name.map(Box::new),
291 })
292 }
293 }
294
295 Some(TypeParameter::Interface(interface_name)) => {
296 let filtered_by_interface = self.filter_by_interface(&interface_name)?;
297
298 let dependency_key = if filtered_by_interface.dependencies.len() == 1 {
299 filtered_by_interface
300 .dependencies
301 .iter()
302 .next()
303 .map(|(k, _)| k.clone())
304 .unwrap()
305 } else {
306 return Err(format!(
307 "interface `{interface_name}` is ambiguous across components"
308 ));
309 };
310
311 Ok(InstanceCreationType::WitWorker {
312 component_info: Some(dependency_key.clone()),
313 worker_name: worker_name.map(Box::new),
314 })
315 }
316
317 _ => Ok(InstanceCreationType::WitWorker {
318 component_info: None,
319 worker_name: worker_name.map(Box::new),
320 }),
321 }
322 }
323
324 pub fn from_raw(
325 component_and_exports: Vec<(ComponentDependencyKey, &Vec<AnalysedExport>)>,
326 ) -> Result<Self, String> {
327 let mut dependencies = BTreeMap::new();
328
329 for (component_info, exports) in component_and_exports {
330 let function_type_registry = FunctionTypeRegistry::from_export_metadata(exports);
331 let function_dictionary =
332 FunctionDictionary::from_function_type_registry(&function_type_registry)?;
333 dependencies.insert(component_info, function_dictionary);
334 }
335
336 Ok(ComponentDependencies { dependencies })
337 }
338}