1use crate::parser::PackageName;
2use crate::type_parameter::InterfaceName;
3use crate::FunctionName;
4use crate::{
5 ComponentDependency, ComponentDependencyKey, Expr, FullyQualifiedResourceConstructor,
6 FunctionDictionary, FunctionType, ResourceMethodDictionary,
7};
8use std::collections::{BTreeMap, HashMap, HashSet};
9use std::sync::Arc;
10
11use std::fmt::Debug;
12use std::ops::Deref;
13
14#[derive(Debug, Hash, Clone, Eq, PartialEq, PartialOrd, Ord)]
22pub enum InstanceType {
23 Global {
25 worker_name: Option<Box<Expr>>,
26 component: Arc<ComponentDependency>,
28 },
29
30 Resource {
33 analysed_resource_id: u64,
34 analysed_resource_mode: u8,
35 worker_name: Option<Box<Expr>>,
36 package_name: Option<PackageName>,
37 interface_name: Option<InterfaceName>,
38 resource_constructor: String,
39 resource_args: Vec<Expr>,
40 component_dependency_key: ComponentDependencyKey,
41 resource_method_dictionary: ResourceMethodDictionary,
42 },
43}
44
45impl InstanceType {
46 pub fn narrow_to_single_component(
47 &mut self,
48 component_dependency_key: &ComponentDependencyKey,
49 ) {
50 match self {
51 InstanceType::Global { component, .. } => {
52 Arc::make_mut(component).narrow_to_component(component_dependency_key);
53 }
54 InstanceType::Resource { .. } => {}
56 }
57 }
58
59 pub fn set_worker_name(&mut self, worker_name: Expr) {
60 match self {
61 InstanceType::Global {
62 worker_name: wn, ..
63 } => {
64 *wn = Some(Box::new(worker_name));
65 }
66 InstanceType::Resource {
67 worker_name: wn, ..
68 } => {
69 *wn = Some(Box::new(worker_name));
70 }
71 }
72 }
73
74 pub fn worker_mut(&mut self) -> Option<&mut Box<Expr>> {
75 match self {
76 InstanceType::Global { worker_name, .. } => worker_name.as_mut(),
77 InstanceType::Resource { worker_name, .. } => worker_name.as_mut(),
78 }
79 }
80
81 pub fn worker(&self) -> Option<&Expr> {
82 match self {
83 InstanceType::Global { worker_name, .. } => worker_name.as_ref().map(|v| v.deref()),
84 InstanceType::Resource { worker_name, .. } => worker_name.as_ref().map(|v| v.deref()),
85 }
86 }
87
88 pub fn get_resource_instance_type(
89 &self,
90 fully_qualified_resource_constructor: FullyQualifiedResourceConstructor,
91 resource_args: Vec<Expr>,
92 worker_name: Option<Box<Expr>>,
93 analysed_resource_id: u64,
94 analysed_resource_mode: u8,
95 ) -> Result<InstanceType, String> {
96 let interface_name = fully_qualified_resource_constructor.interface_name.clone();
97 let package_name = fully_qualified_resource_constructor.package_name.clone();
98 let resource_constructor_name = fully_qualified_resource_constructor.resource_name.clone();
99
100 let dependencies = self.component_dependency();
101 let mut resource_method_dict = BTreeMap::new();
102
103 for (name, typ) in dependencies.function_dictionary.name_and_types.iter() {
104 if let FunctionName::ResourceMethod(resource_method) = name {
105 if resource_method.resource_name == resource_constructor_name
106 && resource_method.interface_name == interface_name
107 && resource_method.package_name == package_name
108 {
109 resource_method_dict.insert(resource_method.clone(), typ.clone());
110 }
111 }
112 }
113
114 let component_dependency_key = dependencies.key.clone();
115 let resource_methods = resource_method_dict;
116
117 if !resource_methods.is_empty() {
118 let resource_method_dictionary = ResourceMethodDictionary {
119 map: resource_methods,
120 };
121
122 Ok(InstanceType::Resource {
123 worker_name,
124 package_name,
125 interface_name,
126 resource_constructor: resource_constructor_name,
127 resource_args,
128 component_dependency_key,
129 resource_method_dictionary,
130 analysed_resource_id,
131 analysed_resource_mode,
132 })
133 } else {
134 Err(format!(
135 "No components found have the resource constructor '{resource_constructor_name}'"
136 ))
137 }
138 }
139
140 pub fn interface_name(&self) -> Option<InterfaceName> {
141 match self {
142 InstanceType::Global { .. } => None,
143 InstanceType::Resource { interface_name, .. } => interface_name.clone(),
144 }
145 }
146
147 pub fn package_name(&self) -> Option<PackageName> {
148 match self {
149 InstanceType::Global { .. } => None,
150 InstanceType::Resource { package_name, .. } => package_name.clone(),
151 }
152 }
153
154 pub fn worker_name(&self) -> Option<Box<Expr>> {
155 match self {
156 InstanceType::Global { worker_name, .. } => worker_name.clone(),
157 InstanceType::Resource { worker_name, .. } => worker_name.clone(),
158 }
159 }
160
161 pub fn get_function(
162 &self,
163 method_name: &str,
164 ) -> Result<(ComponentDependencyKey, Function), String> {
165 search_function_in_instance(self, method_name)
166 }
167
168 pub fn resource_method_dictionary(&self) -> FunctionDictionary {
170 let name_and_types = self
171 .component_dependency()
172 .function_dictionary
173 .name_and_types
174 .iter()
175 .filter(|(f, _)| matches!(f, FunctionName::ResourceMethod(_)))
176 .map(|(f, t)| (f.clone(), t.clone()))
177 .collect();
178
179 FunctionDictionary { name_and_types }
180 }
181
182 pub fn function_dict_without_resource_methods(&self) -> FunctionDictionary {
183 let name_and_types = self
184 .component_dependency()
185 .function_dictionary
186 .name_and_types
187 .iter()
188 .filter(|(f, _)| {
189 !matches!(f, FunctionName::ResourceMethod(_))
190 && !matches!(f, FunctionName::Variant(_))
191 && !matches!(f, FunctionName::Enum(_))
192 })
193 .map(|(f, t)| (f.clone(), t.clone()))
194 .collect();
195
196 FunctionDictionary { name_and_types }
197 }
198
199 pub fn component_dependency(&self) -> ComponentDependency {
200 match self {
201 InstanceType::Global { component, .. } => (**component).clone(),
202 InstanceType::Resource {
203 resource_method_dictionary,
204 component_dependency_key,
205 ..
206 } => {
207 let function_dictionary = FunctionDictionary::from(resource_method_dictionary);
208
209 ComponentDependency {
210 key: component_dependency_key.clone(),
211 function_dictionary,
212 }
213 }
214 }
215 }
216
217 pub fn from(
218 dependency: Arc<ComponentDependency>,
219 worker_name: Option<&Expr>,
220 ) -> Result<InstanceType, String> {
221 Ok(InstanceType::Global {
222 worker_name: worker_name.cloned().map(Box::new),
223 component: dependency,
224 })
225 }
226}
227
228#[derive(Debug, Clone)]
229pub struct Function {
230 pub function_name: FunctionName,
231 pub function_type: FunctionType,
232}
233
234fn search_function_in_instance(
235 instance: &InstanceType,
236 function_name: &str,
237) -> Result<(ComponentDependencyKey, Function), String> {
238 let dependencies = instance.component_dependency();
239 let function_dictionary = &dependencies.function_dictionary;
240 let key = dependencies.key.clone();
241
242 let functions: Vec<&(FunctionName, FunctionType)> = function_dictionary
243 .name_and_types
244 .iter()
245 .filter(|(f, _)| f.name() == function_name)
246 .collect();
247
248 if functions.is_empty() {
249 return Err(format!("function '{function_name}' not found"));
250 }
251
252 let mut package_map: HashMap<Option<PackageName>, HashSet<Option<InterfaceName>>> =
253 HashMap::new();
254
255 for (fqfn, _) in &functions {
256 package_map
257 .entry(fqfn.package_name())
258 .or_default()
259 .insert(fqfn.interface_name());
260 }
261
262 match package_map.len() {
263 1 => {
264 let interfaces = package_map.values().flatten().cloned().collect();
265 let function = search_function_in_single_package(interfaces, functions, function_name)?;
266 Ok((key, function))
267 }
268 _ => {
269 let function = search_function_in_multiple_packages(function_name, package_map)?;
270 Ok((key, function))
271 }
272 }
273}
274
275fn search_function_in_single_package(
276 interfaces: HashSet<Option<InterfaceName>>,
277 functions: Vec<&(FunctionName, FunctionType)>,
278 function_name: &str,
279) -> Result<Function, String> {
280 if interfaces.len() == 1 {
281 let (fqfn, ftype) = &functions[0];
282 Ok(Function {
283 function_name: fqfn.clone(),
284 function_type: ftype.clone(),
285 })
286 } else {
287 let mut interfaces = interfaces
288 .into_iter()
289 .filter_map(|iface| iface.map(|i| i.name))
290 .collect::<Vec<_>>();
291
292 interfaces.sort();
293
294 Err(format!(
295 "multiple interfaces contain function '{function_name}'. Rib does not currently support disambiguating instance method names across interfaces. interfaces: {}",
296 interfaces.join(", ")
297 ))
298 }
299}
300
301fn search_function_in_multiple_packages(
302 function_name: &str,
303 package_map: HashMap<Option<PackageName>, HashSet<Option<InterfaceName>>>,
304) -> Result<Function, String> {
305 let mut error_msg = format!(
306 "function '{function_name}' exists in multiple packages. Rib does not currently support disambiguating instance method names in this case. Conflicting exports: "
307 );
308
309 let mut package_interface_list = package_map
310 .into_iter()
311 .filter_map(|(pkg, interfaces)| {
312 pkg.map(|p| {
313 let mut interface_list = interfaces
314 .into_iter()
315 .filter_map(|iface| iface.map(|i| i.name))
316 .collect::<Vec<_>>();
317
318 interface_list.sort();
319
320 if interface_list.is_empty() {
321 format!("{p}")
322 } else {
323 format!("{} (interfaces: {})", p, interface_list.join(", "))
324 }
325 })
326 })
327 .collect::<Vec<_>>();
328
329 package_interface_list.sort();
330
331 error_msg.push_str(&package_interface_list.join(", "));
332 Err(error_msg)
333}