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