rib/
instance_type.rs

1use crate::parser::{PackageName, TypeParameter};
2use crate::rib_compilation_error::RibCompilationError;
3use crate::type_parameter::InterfaceName;
4use crate::{
5    DynamicParsedFunctionName, Expr, FunctionCallError, FunctionTypeRegistry, InferredType,
6    RegistryKey, RegistryValue,
7};
8use golem_api_grpc::proto::golem::rib::instance_type::Instance;
9use golem_api_grpc::proto::golem::rib::{
10    function_name_type, FullyQualifiedFunctionName as ProtoFullyQualifiedFunctionName,
11    FullyQualifiedResourceConstructor as ProtoFullyQualifiedResourceConstructor,
12    FullyQualifiedResourceMethod as ProtoFullyQualifiedResourceMethod,
13    FunctionDictionary as ProtoFunctionDictionary, FunctionNameType as ProtoFunctionName,
14    FunctionType as ProtoFunctionType, InstanceType as ProtoInstanceType,
15    InterfaceName as ProtoInterfaceName, PackageName as ProtoPackageName,
16    ResourceMethodDictionary as ProtoResourceMethodDictionary,
17};
18use golem_wasm_ast::analysis::AnalysedType;
19use std::collections::{HashMap, HashSet};
20use std::convert::TryFrom;
21use std::fmt::{Debug, Display, Formatter};
22use std::ops::Deref;
23
24// InstanceType will be the type (`InferredType`) of the variable associated with creation of an instance
25// This will be more or less a propagation of the original component metadata (structured as FunctionTypeRegistry),
26// but with better structure and mandates the fact that it belongs to a specific component
27// with better lookups in terms of namespace:package and interfaces.
28// Here we will add the resource type as well as the resource creation itself can be be part of this InstanceType
29// allowing lazy loading of resource and invoke the functions in them!
30// The distinction is only to disallow compiler to see only the functions that are part of a location (package/interface/package-interface/resoruce or all)
31#[derive(Hash, Clone, Eq, PartialEq, PartialOrd, Ord)]
32pub enum InstanceType {
33    // Holds functions across every package and interface in the component
34    Global {
35        worker_name: Option<Box<Expr>>,
36        functions_global: FunctionDictionary,
37    },
38
39    // Holds functions across every interface in the package
40    Package {
41        worker_name: Option<Box<Expr>>,
42        package_name: PackageName,
43        functions_in_package: FunctionDictionary,
44    },
45
46    // Holds all functions across (may be across packages) for a specific interface
47    Interface {
48        worker_name: Option<Box<Expr>>,
49        interface_name: InterfaceName,
50        functions_in_interface: FunctionDictionary,
51    },
52
53    // Most granular level, holds functions for a specific package and interface
54    PackageInterface {
55        worker_name: Option<Box<Expr>>,
56        package_name: PackageName,
57        interface_name: InterfaceName,
58        functions_in_package_interface: FunctionDictionary,
59    },
60
61    // Holds the resource creation and the functions in the resource
62    // that may or may not be addressed
63    Resource {
64        worker_name: Option<Box<Expr>>,
65        package_name: Option<PackageName>,
66        interface_name: Option<InterfaceName>,
67        resource_constructor: String,
68        resource_args: Vec<Expr>,
69        resource_method_dict: ResourceMethodDictionary,
70    },
71}
72
73impl Debug for InstanceType {
74    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
75        write!(f, "InstanceType")
76    }
77}
78
79impl InstanceType {
80    pub fn set_worker_name(&mut self, worker_name: Expr) {
81        match self {
82            InstanceType::Global {
83                worker_name: wn, ..
84            } => {
85                *wn = Some(Box::new(worker_name));
86            }
87            InstanceType::Package {
88                worker_name: wn, ..
89            } => {
90                *wn = Some(Box::new(worker_name));
91            }
92            InstanceType::Interface {
93                worker_name: wn, ..
94            } => {
95                *wn = Some(Box::new(worker_name));
96            }
97            InstanceType::PackageInterface {
98                worker_name: wn, ..
99            } => {
100                *wn = Some(Box::new(worker_name));
101            }
102            InstanceType::Resource {
103                worker_name: wn, ..
104            } => {
105                *wn = Some(Box::new(worker_name));
106            }
107        }
108    }
109
110    pub fn worker_mut(&mut self) -> Option<&mut Box<Expr>> {
111        match self {
112            InstanceType::Global { worker_name, .. } => worker_name.as_mut(),
113            InstanceType::Package { worker_name, .. } => worker_name.as_mut(),
114            InstanceType::Interface { worker_name, .. } => worker_name.as_mut(),
115            InstanceType::PackageInterface { worker_name, .. } => worker_name.as_mut(),
116            InstanceType::Resource { worker_name, .. } => worker_name.as_mut(),
117        }
118    }
119
120    pub fn worker(&self) -> Option<&Expr> {
121        match self {
122            InstanceType::Global { worker_name, .. } => worker_name.as_ref().map(|v| v.deref()),
123            InstanceType::Package { worker_name, .. } => worker_name.as_ref().map(|v| v.deref()),
124            InstanceType::Interface { worker_name, .. } => worker_name.as_ref().map(|v| v.deref()),
125            InstanceType::PackageInterface { worker_name, .. } => {
126                worker_name.as_ref().map(|v| v.deref())
127            }
128            InstanceType::Resource { worker_name, .. } => worker_name.as_ref().map(|v| v.deref()),
129        }
130    }
131
132    // Get InstanceType::Resource from the fully qualified resource constructor
133    // from an existing instance type
134    pub fn get_resource_instance_type(
135        &self,
136        fully_qualified_resource_constructor: FullyQualifiedResourceConstructor,
137        resource_args: Vec<Expr>,
138        worker_name: Option<Box<Expr>>,
139    ) -> InstanceType {
140        let interface_name = fully_qualified_resource_constructor.interface_name.clone();
141        let package_name = fully_qualified_resource_constructor.package_name.clone();
142        let resource_constructor_name = fully_qualified_resource_constructor.resource_name.clone();
143
144        let mut resource_method_dict = vec![];
145        for (f, function_type) in self.function_dict().map.iter() {
146            if let FunctionName::ResourceMethod(resource_method) = f {
147                if resource_method.resource_name == resource_constructor_name
148                    && resource_method.interface_name == interface_name
149                    && resource_method.package_name == package_name
150                {
151                    resource_method_dict.push((resource_method.clone(), function_type.clone()));
152                }
153            }
154        }
155
156        let resource_method_dict = ResourceMethodDictionary {
157            map: resource_method_dict,
158        };
159
160        InstanceType::Resource {
161            worker_name,
162            package_name,
163            interface_name,
164            resource_constructor: resource_constructor_name,
165            resource_args,
166            resource_method_dict,
167        }
168    }
169
170    pub fn interface_name(&self) -> Option<InterfaceName> {
171        match self {
172            InstanceType::Global { .. } => None,
173            InstanceType::Package { .. } => None,
174            InstanceType::Interface { interface_name, .. } => Some(interface_name.clone()),
175            InstanceType::PackageInterface { interface_name, .. } => Some(interface_name.clone()),
176            InstanceType::Resource { interface_name, .. } => interface_name.clone(),
177        }
178    }
179
180    pub fn package_name(&self) -> Option<PackageName> {
181        match self {
182            InstanceType::Global { .. } => None,
183            InstanceType::Package { package_name, .. } => Some(package_name.clone()),
184            InstanceType::Interface { .. } => None,
185            InstanceType::PackageInterface { package_name, .. } => Some(package_name.clone()),
186            InstanceType::Resource { package_name, .. } => package_name.clone(),
187        }
188    }
189
190    pub fn worker_name(&self) -> Option<Box<Expr>> {
191        match self {
192            InstanceType::Global { worker_name, .. } => worker_name.clone(),
193            InstanceType::Package { worker_name, .. } => worker_name.clone(),
194            InstanceType::Interface { worker_name, .. } => worker_name.clone(),
195            InstanceType::PackageInterface { worker_name, .. } => worker_name.clone(),
196            InstanceType::Resource { worker_name, .. } => worker_name.clone(),
197        }
198    }
199    pub fn get_function(
200        &self,
201        expr: Expr,
202        method_name: &str,
203        type_parameter: Option<TypeParameter>,
204    ) -> Result<Function, FunctionCallError> {
205        match type_parameter {
206            Some(tp) => match tp {
207                TypeParameter::Interface(iface) => {
208                    let interfaces = self
209                        .function_dict()
210                        .map
211                        .into_iter()
212                        .filter(|(f, _)| f.interface_name() == Some(iface.clone()))
213                        .collect::<Vec<_>>();
214
215                    if interfaces.is_empty() {
216                        return Err(FunctionCallError::InvalidFunctionCall {
217                            function_name: method_name.to_string(),
218                            expr,
219                            message: format!("Interface '{}' not found", iface),
220                        });
221                    }
222
223                    let functions = interfaces
224                        .into_iter()
225                        .filter(|(f, _)| f.name() == method_name)
226                        .collect::<Vec<_>>();
227
228                    if functions.is_empty() {
229                        return Err(FunctionCallError::InvalidFunctionCall {
230                            function_name: method_name.to_string(),
231                            expr,
232                            message: format!(
233                                "Function '{}' not found in interface '{}'",
234                                method_name, iface
235                            ),
236                        });
237                    }
238
239                    // There is only 1 interface, and there cannot exist any more conflicts
240                    // with an interface
241                    if functions.len() == 1 {
242                        let (fqfn, ftype) = &functions[0];
243                        Ok(Function {
244                            function_name: fqfn.clone(),
245                            function_type: ftype.clone(),
246                        })
247                    } else {
248                        search_function_in_instance(self, method_name).map_err(|err| {
249                            FunctionCallError::InvalidFunctionCall {
250                                function_name: method_name.to_string(),
251                                expr,
252                                message: err,
253                            }
254                        })
255                    }
256                }
257
258                TypeParameter::PackageName(pkg) => {
259                    let packages = self
260                        .function_dict()
261                        .map
262                        .into_iter()
263                        .filter(|(f, _)| f.package_name() == Some(pkg.clone()))
264                        .collect::<Vec<_>>();
265
266                    if packages.is_empty() {
267                        return Err(FunctionCallError::InvalidFunctionCall {
268                            function_name: method_name.to_string(),
269                            expr,
270                            message: format!("package '{}' not found", pkg),
271                        });
272                    }
273
274                    let functions = packages
275                        .into_iter()
276                        .filter(|(f, _)| f.name() == method_name)
277                        .collect::<Vec<_>>();
278
279                    if functions.is_empty() {
280                        return Err(FunctionCallError::InvalidFunctionCall {
281                            function_name: method_name.to_string(),
282                            expr,
283                            message: format!(
284                                "function '{}' not found in package '{}'",
285                                method_name, pkg
286                            ),
287                        });
288                    }
289
290                    if functions.len() == 1 {
291                        let (fqfn, ftype) = &functions[0];
292                        Ok(Function {
293                            function_name: fqfn.clone(),
294                            function_type: ftype.clone(),
295                        })
296                    } else {
297                        search_function_in_instance(self, method_name).map_err(|err| {
298                            FunctionCallError::InvalidFunctionCall {
299                                function_name: method_name.to_string(),
300                                expr,
301                                message: err,
302                            }
303                        })
304                    }
305                }
306
307                TypeParameter::FullyQualifiedInterface(fq_iface) => {
308                    let functions = self
309                        .function_dict()
310                        .map
311                        .into_iter()
312                        .filter(|(f, _)| {
313                            f.package_name() == Some(fq_iface.package_name.clone())
314                                && f.interface_name() == Some(fq_iface.interface_name.clone())
315                                && f.name() == method_name
316                        })
317                        .collect::<Vec<_>>();
318
319                    if functions.is_empty() {
320                        return Err(FunctionCallError::InvalidFunctionCall {
321                            function_name: method_name.to_string(),
322                            expr,
323                            message: format!(
324                                "function '{}' not found in interface '{}'",
325                                method_name, fq_iface
326                            ),
327                        });
328                    }
329
330                    if functions.len() == 1 {
331                        let (fqfn, ftype) = &functions[0];
332                        Ok(Function {
333                            function_name: fqfn.clone(),
334                            function_type: ftype.clone(),
335                        })
336                    } else {
337                        search_function_in_instance(self, method_name).map_err(|err| {
338                            FunctionCallError::InvalidFunctionCall {
339                                function_name: method_name.to_string(),
340                                expr,
341                                message: err,
342                            }
343                        })
344                    }
345                }
346            },
347            None => search_function_in_instance(self, method_name).map_err(|err| {
348                FunctionCallError::InvalidFunctionCall {
349                    function_name: method_name.to_string(),
350                    expr,
351                    message: err,
352                }
353            }),
354        }
355    }
356
357    pub fn function_dict(&self) -> FunctionDictionary {
358        match self {
359            InstanceType::Global {
360                functions_global: function_dict,
361                ..
362            } => function_dict.clone(),
363            InstanceType::Package {
364                functions_in_package: function_dict,
365                ..
366            } => function_dict.clone(),
367            InstanceType::Interface {
368                functions_in_interface: function_dict,
369                ..
370            } => function_dict.clone(),
371            InstanceType::PackageInterface {
372                functions_in_package_interface: function_dict,
373                ..
374            } => function_dict.clone(),
375            InstanceType::Resource {
376                resource_method_dict,
377                ..
378            } => resource_method_dict.into(),
379        }
380    }
381
382    pub fn from(
383        registry: FunctionTypeRegistry,
384        worker_name: Option<Expr>,
385        type_parameter: Option<TypeParameter>,
386        expr: Expr,
387    ) -> Result<InstanceType, RibCompilationError> {
388        let function_dict = FunctionDictionary::from_function_type_registry(registry, expr)?;
389
390        match type_parameter {
391            None => Ok(InstanceType::Global {
392                worker_name: worker_name.map(Box::new),
393                functions_global: function_dict,
394            }),
395            Some(type_parameter) => match type_parameter {
396                TypeParameter::Interface(interface_name) => {
397                    let function_dict = FunctionDictionary {
398                        map: function_dict
399                            .map
400                            .into_iter()
401                            .filter(|(f, _)| f.interface_name() == Some(interface_name.clone()))
402                            .collect::<Vec<_>>(),
403                    };
404
405                    Ok(InstanceType::Interface {
406                        worker_name: worker_name.map(Box::new),
407                        interface_name,
408                        functions_in_interface: function_dict,
409                    })
410                }
411                TypeParameter::PackageName(package_name) => {
412                    let function_dict = FunctionDictionary {
413                        map: function_dict
414                            .map
415                            .into_iter()
416                            .filter(|(f, _)| f.package_name() == Some(package_name.clone()))
417                            .collect(),
418                    };
419
420                    Ok(InstanceType::Package {
421                        worker_name: worker_name.map(Box::new),
422                        package_name,
423                        functions_in_package: function_dict,
424                    })
425                }
426                TypeParameter::FullyQualifiedInterface(fq_interface) => {
427                    let function_dict = FunctionDictionary {
428                        map: function_dict
429                            .map
430                            .into_iter()
431                            .filter(|(f, _)| {
432                                f.package_name() == Some(fq_interface.package_name.clone())
433                                    && f.interface_name()
434                                        == Some(fq_interface.interface_name.clone())
435                            })
436                            .collect(),
437                    };
438
439                    Ok(InstanceType::PackageInterface {
440                        worker_name: worker_name.map(Box::new),
441                        package_name: fq_interface.package_name,
442                        interface_name: fq_interface.interface_name,
443                        functions_in_package_interface: function_dict,
444                    })
445                }
446            },
447        }
448    }
449}
450
451#[derive(Debug, Clone)]
452pub struct Function {
453    pub function_name: FunctionName,
454    pub function_type: FunctionType,
455}
456
457#[derive(Debug, Hash, Clone, Eq, PartialEq, Ord, PartialOrd)]
458pub struct FunctionDictionary {
459    pub map: Vec<(FunctionName, FunctionType)>,
460}
461
462impl FunctionDictionary {
463    pub fn function_names(&self) -> Vec<String> {
464        self.map.iter().map(|(f, _)| f.name()).collect::<Vec<_>>()
465    }
466}
467
468#[derive(Debug, Hash, Clone, Eq, PartialEq, PartialOrd, Ord)]
469pub struct ResourceMethodDictionary {
470    pub map: Vec<(FullyQualifiedResourceMethod, FunctionType)>,
471}
472
473impl From<&ResourceMethodDictionary> for FunctionDictionary {
474    fn from(value: &ResourceMethodDictionary) -> Self {
475        FunctionDictionary {
476            map: value
477                .map
478                .iter()
479                .map(|(k, v)| (FunctionName::ResourceMethod(k.clone()), v.clone()))
480                .collect(),
481        }
482    }
483}
484
485#[derive(Debug, Hash, Clone, Eq, PartialEq, PartialOrd, Ord)]
486pub struct ResourceMethod {
487    constructor_name: String,
488    resource_name: String,
489}
490
491impl FunctionDictionary {
492    pub fn from_function_type_registry(
493        registry: FunctionTypeRegistry,
494        expr: Expr,
495    ) -> Result<FunctionDictionary, RibCompilationError> {
496        let mut map = vec![];
497
498        for (key, value) in registry.types {
499            match value {
500                RegistryValue::Function {
501                    parameter_types,
502                    return_types,
503                } => match key {
504                    RegistryKey::FunctionName(function_name) => {
505                        let function_name = resolve_function_name(None, None, &function_name)
506                            .map_err(|err| FunctionCallError::InvalidFunctionCall {
507                                function_name: function_name.clone(),
508                                message: err,
509                                expr: expr.clone(),
510                            })?;
511
512                        map.push((
513                            function_name,
514                            FunctionType {
515                                parameter_types: parameter_types
516                                    .into_iter()
517                                    .map(|x| x.into())
518                                    .collect(),
519                                return_type: return_types.into_iter().map(|x| x.into()).collect(),
520                            },
521                        ));
522                    }
523
524                    RegistryKey::FunctionNameWithInterface {
525                        interface_name,
526                        function_name,
527                    } => {
528                        let type_parameter = TypeParameter::from_str(interface_name.as_str())
529                            .map_err(|err| FunctionCallError::InvalidGenericTypeParameter {
530                                generic_type_parameter: interface_name.clone(),
531                                message: err,
532                                expr: expr.clone(),
533                            })?;
534
535                        let interface_name = type_parameter.get_interface_name();
536                        let package_name = type_parameter.get_package_name();
537
538                        let function_name =
539                            resolve_function_name(package_name, interface_name, &function_name)
540                                .map_err(|err| FunctionCallError::InvalidFunctionCall {
541                                    function_name: function_name.clone(),
542                                    message: err,
543                                    expr: expr.clone(),
544                                })?;
545
546                        map.push((
547                            function_name,
548                            FunctionType {
549                                parameter_types: parameter_types
550                                    .into_iter()
551                                    .map(|x| x.into())
552                                    .collect(),
553                                return_type: return_types.into_iter().map(|x| x.into()).collect(),
554                            },
555                        ));
556                    }
557                },
558
559                _ => continue,
560            };
561        }
562
563        Ok(FunctionDictionary { map })
564    }
565}
566
567fn resolve_function_name(
568    package_name: Option<PackageName>,
569    interface_name: Option<InterfaceName>,
570    function_name: &str,
571) -> Result<FunctionName, String> {
572    match get_resource_name(function_name) {
573        Some(resource_name) => Ok(FunctionName::ResourceConstructor(
574            FullyQualifiedResourceConstructor {
575                package_name,
576                interface_name,
577                resource_name,
578            },
579        )),
580        None => match get_resource_method_name(function_name) {
581            Ok(Some((constructor, method))) => {
582                Ok(FunctionName::ResourceMethod(FullyQualifiedResourceMethod {
583                    package_name,
584                    interface_name,
585                    resource_name: constructor,
586                    method_name: method,
587                }))
588            }
589            Ok(None) => Ok(FunctionName::Function(FullyQualifiedFunctionName {
590                package_name,
591                interface_name,
592                function_name: function_name.to_string(),
593            })),
594
595            Err(e) => Err(format!("Invalid function call. {}", e)),
596        },
597    }
598}
599
600fn get_resource_name(function_name: &str) -> Option<String> {
601    if function_name.starts_with("[constructor]") {
602        Some(
603            function_name
604                .trim_start_matches("[constructor]")
605                .to_string(),
606        )
607    } else {
608        None
609    }
610}
611
612fn get_resource_method_name(function_name: &str) -> Result<Option<(String, String)>, String> {
613    if function_name.starts_with("[method]") {
614        let constructor_and_method = function_name.trim_start_matches("[method]").to_string();
615        let mut constructor_and_method = constructor_and_method.split('.');
616        let constructor = constructor_and_method.next();
617        let method = constructor_and_method.next();
618
619        match (constructor, method) {
620            (Some(constructor), Some(method)) => {
621                Ok(Some((constructor.to_string(), method.to_string())))
622            }
623            _ => Err(format!("Invalid resource method name: {}", function_name)),
624        }
625    } else if function_name.starts_with("[drop]") {
626        let constructor = function_name.trim_start_matches("[drop]").to_string();
627        Ok(Some((constructor, "drop".to_string())))
628    } else {
629        Ok(None)
630    }
631}
632
633#[derive(Debug, Hash, Clone, Eq, PartialEq, Ord, PartialOrd)]
634pub enum FunctionName {
635    Function(FullyQualifiedFunctionName),
636    ResourceConstructor(FullyQualifiedResourceConstructor),
637    ResourceMethod(FullyQualifiedResourceMethod),
638}
639
640impl FunctionName {
641    pub fn interface_name(&self) -> Option<InterfaceName> {
642        match self {
643            FunctionName::Function(fqfn) => fqfn.interface_name.clone(),
644            FunctionName::ResourceConstructor(fqfn) => fqfn.interface_name.clone(),
645            FunctionName::ResourceMethod(resource_method) => resource_method.interface_name.clone(),
646        }
647    }
648
649    pub fn package_name(&self) -> Option<PackageName> {
650        match self {
651            FunctionName::Function(fqfn) => fqfn.package_name.clone(),
652            FunctionName::ResourceConstructor(fqfn) => fqfn.package_name.clone(),
653            FunctionName::ResourceMethod(fqfn) => fqfn.package_name.clone(),
654        }
655    }
656
657    pub fn name(&self) -> String {
658        match self {
659            FunctionName::Function(fqfn) => fqfn.function_name.to_string(),
660            FunctionName::ResourceConstructor(fqfn) => fqfn.resource_name.to_string(),
661            FunctionName::ResourceMethod(fqfn) => fqfn.method_name.to_string(),
662        }
663    }
664}
665
666#[derive(Debug, Hash, Clone, Eq, PartialEq, Ord, PartialOrd)]
667pub struct FullyQualifiedResourceConstructor {
668    pub package_name: Option<PackageName>,
669    pub interface_name: Option<InterfaceName>,
670    pub resource_name: String,
671}
672
673#[derive(Debug, Hash, Clone, Eq, PartialEq, Ord, PartialOrd)]
674pub struct FullyQualifiedFunctionName {
675    package_name: Option<PackageName>,
676    interface_name: Option<InterfaceName>,
677    function_name: String,
678}
679
680#[derive(Debug, Hash, Clone, Eq, PartialEq, Ord, PartialOrd)]
681pub struct FullyQualifiedResourceMethod {
682    package_name: Option<PackageName>,
683    interface_name: Option<InterfaceName>,
684    resource_name: String,
685    method_name: String,
686}
687
688impl FullyQualifiedResourceMethod {
689    // We rely on the fully parsed function name itself to retrieve the original function name
690    pub fn dynamic_parsed_function_name(
691        &self,
692        resource_args: Vec<Expr>,
693    ) -> Result<DynamicParsedFunctionName, String> {
694        let mut dynamic_parsed_str = String::new();
695
696        // Construct the package/interface prefix
697        if let Some(package) = &self.package_name {
698            dynamic_parsed_str.push_str(&package.to_string());
699            dynamic_parsed_str.push('/');
700        }
701
702        if let Some(interface) = &self.interface_name {
703            dynamic_parsed_str.push_str(&interface.to_string());
704            dynamic_parsed_str.push('.');
705        }
706
707        // Start the dynamic function name with resource
708        dynamic_parsed_str.push('{');
709        dynamic_parsed_str.push_str(&self.resource_name);
710
711        // If arguments exist, format them inside parentheses
712        if !resource_args.is_empty() {
713            dynamic_parsed_str.push('(');
714            dynamic_parsed_str.push_str(
715                &resource_args
716                    .into_iter()
717                    .map(|x| x.to_string())
718                    .collect::<Vec<_>>()
719                    .join(", "),
720            );
721            dynamic_parsed_str.push(')');
722        }
723
724        // Append the method name
725        dynamic_parsed_str.push('.');
726        dynamic_parsed_str.push_str(&self.method_name);
727        dynamic_parsed_str.push('}');
728
729        DynamicParsedFunctionName::parse(dynamic_parsed_str)
730    }
731
732    pub fn method_name(&self) -> &String {
733        &self.method_name
734    }
735}
736
737impl Display for FullyQualifiedFunctionName {
738    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
739        if let Some(package_name) = &self.package_name {
740            write!(f, "{}", package_name)?
741        }
742
743        if let Some(interface_name) = &self.interface_name {
744            write!(f, "/{}.", interface_name)?;
745            write!(f, "{{{}}}", self.function_name)
746        } else {
747            write!(f, "{}", self.function_name)
748        }
749    }
750}
751
752#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
753pub struct FunctionType {
754    parameter_types: Vec<InferredType>,
755    return_type: Vec<InferredType>,
756}
757
758impl FunctionType {
759    pub fn parameter_types(&self) -> Vec<InferredType> {
760        self.parameter_types.clone()
761    }
762
763    pub fn return_type(&self) -> Vec<InferredType> {
764        self.return_type.clone()
765    }
766}
767
768fn search_function_in_instance(
769    instance: &InstanceType,
770    function_name: &str,
771) -> Result<Function, String> {
772    let functions: Vec<(FunctionName, FunctionType)> = instance
773        .function_dict()
774        .map
775        .into_iter()
776        .filter(|(f, _)| f.name() == *function_name)
777        .collect();
778
779    if functions.is_empty() {
780        return Err(format!("function '{}' not found", function_name));
781    }
782
783    let mut package_map: HashMap<Option<PackageName>, HashSet<Option<InterfaceName>>> =
784        HashMap::new();
785
786    for (fqfn, _) in &functions {
787        package_map
788            .entry(fqfn.package_name())
789            .or_default()
790            .insert(fqfn.interface_name());
791    }
792
793    match package_map.len() {
794        1 => {
795            let interfaces = package_map.values().flatten().cloned().collect();
796            search_function_in_single_package(interfaces, functions, function_name)
797        }
798        _ => search_function_in_multiple_packages(function_name, package_map),
799    }
800}
801
802fn search_function_in_single_package(
803    interfaces: HashSet<Option<InterfaceName>>,
804    functions: Vec<(FunctionName, FunctionType)>,
805    function_name: &str,
806) -> Result<Function, String> {
807    if interfaces.len() == 1 {
808        let (fqfn, ftype) = &functions[0];
809        Ok(Function {
810            function_name: fqfn.clone(),
811            function_type: ftype.clone(),
812        })
813    } else {
814        let mut interfaces = interfaces
815            .into_iter()
816            .filter_map(|iface| iface.map(|i| i.name))
817            .collect::<Vec<_>>();
818
819        interfaces.sort();
820
821        // Multiple interfaces in the same package -> Ask for an interface name
822        Err(format!(
823            "multiple interfaces contain function '{}'. specify an interface name as type parameter from: {}",
824            function_name,
825            interfaces
826                .join(", ")
827        ))
828    }
829}
830
831fn search_function_in_multiple_packages(
832    function_name: &str,
833    package_map: HashMap<Option<PackageName>, HashSet<Option<InterfaceName>>>,
834) -> Result<Function, String> {
835    let mut error_msg = format!(
836        "function '{}' exists in multiple packages. specify a package name as type parameter from: ",
837        function_name
838    );
839
840    let mut package_interface_list = package_map
841        .into_iter()
842        .filter_map(|(pkg, interfaces)| {
843            pkg.map(|p| {
844                let mut interface_list = interfaces
845                    .into_iter()
846                    .filter_map(|iface| iface.map(|i| i.name))
847                    .collect::<Vec<_>>();
848
849                interface_list.sort();
850
851                if interface_list.is_empty() {
852                    format!("{}", p)
853                } else {
854                    format!("{} (interfaces: {})", p, interface_list.join(", "))
855                }
856            })
857        })
858        .collect::<Vec<_>>();
859
860    package_interface_list.sort();
861
862    error_msg.push_str(&package_interface_list.join(", "));
863    Err(error_msg)
864}
865
866impl TryFrom<ProtoFunctionType> for FunctionType {
867    type Error = String;
868
869    fn try_from(proto: ProtoFunctionType) -> Result<Self, Self::Error> {
870        let mut parameter_types = Vec::new();
871        for param in proto.parameter_types {
872            parameter_types.push(InferredType::from(AnalysedType::try_from(&param)?));
873        }
874
875        let mut return_type = Vec::new();
876        for ret in proto.return_type {
877            return_type.push(InferredType::from(AnalysedType::try_from(&ret)?));
878        }
879
880        Ok(Self {
881            parameter_types,
882            return_type,
883        })
884    }
885}
886
887impl TryFrom<ProtoResourceMethodDictionary> for ResourceMethodDictionary {
888    type Error = String;
889
890    fn try_from(proto: ProtoResourceMethodDictionary) -> Result<Self, Self::Error> {
891        let mut map = Vec::new();
892        for resource_method_entry in proto.map {
893            let resource_method = resource_method_entry
894                .key
895                .ok_or("resource method not found")?;
896            let function_type = resource_method_entry
897                .value
898                .ok_or("function type not found")?;
899            let resource_method = FullyQualifiedResourceMethod::try_from(resource_method)?;
900            let function_type = FunctionType::try_from(function_type)?;
901            map.push((resource_method, function_type));
902        }
903        Ok(ResourceMethodDictionary { map })
904    }
905}
906
907impl TryFrom<ProtoFunctionDictionary> for FunctionDictionary {
908    type Error = String;
909
910    fn try_from(value: ProtoFunctionDictionary) -> Result<Self, Self::Error> {
911        let mut map = Vec::new();
912
913        for function_entry in value.map {
914            let function_name = function_entry.key.ok_or("Function name not found")?;
915            let function_type = function_entry.value.ok_or("Function type not found")?;
916
917            let function_name = FunctionName::try_from(function_name)?;
918            let function_type = FunctionType::try_from(function_type)?;
919            map.push((function_name, function_type));
920        }
921
922        Ok(FunctionDictionary { map })
923    }
924}
925
926impl TryFrom<ProtoPackageName> for PackageName {
927    type Error = String;
928
929    fn try_from(proto: ProtoPackageName) -> Result<Self, Self::Error> {
930        Ok(PackageName {
931            namespace: proto.namespace,
932            package_name: proto.package_name,
933            version: proto.version,
934        })
935    }
936}
937
938impl TryFrom<ProtoInterfaceName> for InterfaceName {
939    type Error = String;
940
941    fn try_from(value: ProtoInterfaceName) -> Result<Self, Self::Error> {
942        Ok(InterfaceName {
943            name: value.name,
944            version: value.version,
945        })
946    }
947}
948
949impl TryFrom<ProtoFullyQualifiedFunctionName> for FullyQualifiedFunctionName {
950    type Error = String;
951
952    fn try_from(proto: ProtoFullyQualifiedFunctionName) -> Result<Self, Self::Error> {
953        Ok(FullyQualifiedFunctionName {
954            package_name: proto.package_name.map(TryFrom::try_from).transpose()?,
955            interface_name: proto.interface_name.map(TryFrom::try_from).transpose()?,
956            function_name: proto.function_name,
957        })
958    }
959}
960
961impl TryFrom<ProtoFullyQualifiedResourceMethod> for FullyQualifiedResourceMethod {
962    type Error = String;
963
964    fn try_from(proto: ProtoFullyQualifiedResourceMethod) -> Result<Self, Self::Error> {
965        Ok(FullyQualifiedResourceMethod {
966            resource_name: proto.resource_name,
967            method_name: proto.method_name,
968            package_name: proto.package_name.map(TryFrom::try_from).transpose()?,
969            interface_name: proto.interface_name.map(TryFrom::try_from).transpose()?,
970        })
971    }
972}
973
974impl TryFrom<ProtoFullyQualifiedResourceConstructor> for FullyQualifiedResourceConstructor {
975    type Error = String;
976
977    fn try_from(proto: ProtoFullyQualifiedResourceConstructor) -> Result<Self, Self::Error> {
978        Ok(FullyQualifiedResourceConstructor {
979            package_name: proto.package_name.map(TryFrom::try_from).transpose()?,
980            interface_name: proto.interface_name.map(TryFrom::try_from).transpose()?,
981            resource_name: proto.resource_name,
982        })
983    }
984}
985
986impl TryFrom<ProtoFunctionName> for FunctionName {
987    type Error = String;
988
989    fn try_from(proto: ProtoFunctionName) -> Result<Self, Self::Error> {
990        let proto_function_name = proto.function_name.ok_or("Function name not found")?;
991        match proto_function_name {
992            function_name_type::FunctionName::Function(fqfn) => {
993                Ok(FunctionName::Function(TryFrom::try_from(fqfn)?))
994            }
995            function_name_type::FunctionName::ResourceConstructor(fqfn) => {
996                Ok(FunctionName::ResourceConstructor(TryFrom::try_from(fqfn)?))
997            }
998            function_name_type::FunctionName::ResourceMethod(fqfn) => {
999                Ok(FunctionName::ResourceMethod(TryFrom::try_from(fqfn)?))
1000            }
1001        }
1002    }
1003}
1004
1005impl TryFrom<ProtoInstanceType> for InstanceType {
1006    type Error = String;
1007
1008    fn try_from(value: ProtoInstanceType) -> Result<Self, Self::Error> {
1009        let instance = value.instance.ok_or("Instance not found")?;
1010
1011        match instance {
1012            Instance::Global(global_instance) => {
1013                let functions_global = global_instance
1014                    .functions_global
1015                    .ok_or("Functions global not found")?;
1016
1017                Ok(InstanceType::Global {
1018                    worker_name: global_instance
1019                        .worker_name
1020                        .map(Expr::try_from)
1021                        .transpose()?
1022                        .map(Box::new),
1023                    functions_global: TryFrom::try_from(functions_global)?,
1024                })
1025            }
1026            Instance::Package(package_instance) => {
1027                let package_name = package_instance
1028                    .package_name
1029                    .ok_or("Package name not found")?;
1030                let functions_in_package = package_instance
1031                    .functions_in_package
1032                    .ok_or("Functions in package not found")?;
1033
1034                Ok(InstanceType::Package {
1035                    worker_name: package_instance
1036                        .worker_name
1037                        .map(Expr::try_from)
1038                        .transpose()?
1039                        .map(Box::new),
1040                    package_name: TryFrom::try_from(package_name)?,
1041                    functions_in_package: TryFrom::try_from(functions_in_package)?,
1042                })
1043            }
1044            Instance::Interface(interface_instance) => {
1045                let interface_name = interface_instance
1046                    .interface_name
1047                    .ok_or("Interface name not found")?;
1048                let functions_in_interface = interface_instance
1049                    .functions_in_interface
1050                    .ok_or("Functions in interface not found")?;
1051
1052                Ok(InstanceType::Interface {
1053                    worker_name: interface_instance
1054                        .worker_name
1055                        .map(Expr::try_from)
1056                        .transpose()?
1057                        .map(Box::new),
1058                    interface_name: TryFrom::try_from(interface_name)?,
1059                    functions_in_interface: TryFrom::try_from(functions_in_interface)?,
1060                })
1061            }
1062            Instance::PackageInterface(package_interface_instance) => {
1063                let functions_in_package_interface = package_interface_instance
1064                    .functions_in_package_interface
1065                    .ok_or("Functions in package interface not found")?;
1066
1067                let interface_name = package_interface_instance
1068                    .interface_name
1069                    .ok_or("Interface name not found")?;
1070                let package_name = package_interface_instance
1071                    .package_name
1072                    .ok_or("Package name not found")?;
1073
1074                Ok(InstanceType::PackageInterface {
1075                    worker_name: package_interface_instance
1076                        .worker_name
1077                        .map(Expr::try_from)
1078                        .transpose()?
1079                        .map(Box::new),
1080                    package_name: TryFrom::try_from(package_name)?,
1081                    interface_name: TryFrom::try_from(interface_name)?,
1082                    functions_in_package_interface: TryFrom::try_from(
1083                        functions_in_package_interface,
1084                    )?,
1085                })
1086            }
1087            Instance::Resource(resource_instance) => {
1088                let resource_method_dict = resource_instance
1089                    .resource_method_dict
1090                    .ok_or("Resource method dictionary not found")?;
1091                Ok(InstanceType::Resource {
1092                    worker_name: resource_instance
1093                        .worker_name
1094                        .map(Expr::try_from)
1095                        .transpose()?
1096                        .map(Box::new),
1097                    package_name: resource_instance
1098                        .package_name
1099                        .map(TryFrom::try_from)
1100                        .transpose()?,
1101                    interface_name: resource_instance
1102                        .interface_name
1103                        .map(TryFrom::try_from)
1104                        .transpose()?,
1105                    resource_constructor: resource_instance.resource_constructor,
1106                    resource_args: resource_instance
1107                        .resource_args
1108                        .into_iter()
1109                        .map(TryFrom::try_from)
1110                        .collect::<Result<Vec<Expr>, String>>()?,
1111                    resource_method_dict: TryFrom::try_from(resource_method_dict)?,
1112                })
1113            }
1114        }
1115    }
1116}
1117
1118impl From<PackageName> for ProtoPackageName {
1119    fn from(value: PackageName) -> Self {
1120        ProtoPackageName {
1121            namespace: value.namespace,
1122            package_name: value.package_name,
1123            version: value.version,
1124        }
1125    }
1126}
1127
1128impl From<InterfaceName> for ProtoInterfaceName {
1129    fn from(value: InterfaceName) -> Self {
1130        ProtoInterfaceName {
1131            name: value.name,
1132            version: value.version,
1133        }
1134    }
1135}
1136
1137impl From<FullyQualifiedResourceConstructor> for ProtoFullyQualifiedResourceConstructor {
1138    fn from(value: FullyQualifiedResourceConstructor) -> Self {
1139        ProtoFullyQualifiedResourceConstructor {
1140            package_name: value.package_name.map(ProtoPackageName::from),
1141            interface_name: value.interface_name.map(ProtoInterfaceName::from),
1142            resource_name: value.resource_name,
1143        }
1144    }
1145}