rib/
instance_type.rs

1// Copyright 2024-2025 Golem Cloud
2//
3// Licensed under the Golem Source License v1.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://license.golem.cloud/LICENSE
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::parser::{PackageName, TypeParameter};
16use crate::type_parameter::InterfaceName;
17use crate::FunctionName;
18use crate::{
19    ComponentDependencies, ComponentDependencyKey, Expr, FullyQualifiedResourceConstructor,
20    FunctionDictionary, FunctionType, InferredType, ResourceMethodDictionary,
21};
22use golem_api_grpc::proto::golem::rib::{
23    FullyQualifiedResourceConstructor as ProtoFullyQualifiedResourceConstructor,
24    FunctionType as ProtoFunctionType, InterfaceName as ProtoInterfaceName,
25    PackageName as ProtoPackageName,
26};
27use golem_wasm_ast::analysis::AnalysedType;
28use std::collections::{BTreeMap, HashMap, HashSet};
29use std::convert::TryFrom;
30use std::fmt::Debug;
31use std::ops::Deref;
32
33// `InstanceType` will be the type (`InferredType`) of the variable associated with creation of an instance
34// `InstanceType` is structured to help with compilation logic better. Example: a random `instance()` call
35// is of type `Global` to begin with and as soon as method invocations becomes a real function call,
36// the type of instance becomes more and more precise.
37//
38// Please look at `InstanceCreationType`
39// for a tangible view on the fact that an instance can be either worker or a resource.
40#[derive(Debug, Hash, Clone, Eq, PartialEq, PartialOrd, Ord)]
41pub enum InstanceType {
42    // Holds functions across every package and interface in every component
43    Global {
44        worker_name: Option<Box<Expr>>,
45        component_dependency: ComponentDependencies,
46    },
47
48    // A component can refer to a Package x, which can exist in other components
49    Package {
50        worker_name: Option<Box<Expr>>,
51        package_name: PackageName,
52        component_dependency: ComponentDependencies,
53    },
54
55    // Holds all functions across (may be across packages or components) for a specific interface
56    Interface {
57        worker_name: Option<Box<Expr>>,
58        interface_name: InterfaceName,
59        component_dependency: ComponentDependencies,
60    },
61
62    // Most granular level, holds functions for a specific package and interface
63    // That said, this package and interface may exist in multiple components
64    PackageInterface {
65        worker_name: Option<Box<Expr>>,
66        package_name: PackageName,
67        interface_name: InterfaceName,
68        component_dependency: ComponentDependencies,
69    },
70
71    // Holds the resource creation and the functions in the resource
72    // that may or may not be addressed
73    Resource {
74        analysed_resource_id: u64,
75        analysed_resource_mode: u8,
76        worker_name: Option<Box<Expr>>,
77        package_name: Option<PackageName>,
78        interface_name: Option<InterfaceName>,
79        resource_constructor: String,
80        resource_args: Vec<Expr>,
81        component_dependency_key: ComponentDependencyKey,
82        resource_method_dictionary: ResourceMethodDictionary,
83    },
84}
85
86impl InstanceType {
87    pub fn narrow_to_single_component(
88        &mut self,
89        component_dependency_key: &ComponentDependencyKey,
90    ) {
91        match self {
92            InstanceType::Global {
93                component_dependency,
94                ..
95            } => {
96                component_dependency.narrow_to_component(component_dependency_key);
97            }
98            InstanceType::Package {
99                component_dependency,
100                ..
101            } => {
102                component_dependency.narrow_to_component(component_dependency_key);
103            }
104            InstanceType::Interface {
105                component_dependency,
106                ..
107            } => {
108                component_dependency.narrow_to_component(component_dependency_key);
109            }
110            InstanceType::PackageInterface {
111                component_dependency,
112                ..
113            } => {
114                component_dependency.narrow_to_component(component_dependency_key);
115            }
116            // A resource is already narrowed down to a component
117            InstanceType::Resource { .. } => {}
118        }
119    }
120
121    pub fn set_worker_name(&mut self, worker_name: Expr) {
122        match self {
123            InstanceType::Global {
124                worker_name: wn, ..
125            } => {
126                *wn = Some(Box::new(worker_name));
127            }
128            InstanceType::Package {
129                worker_name: wn, ..
130            } => {
131                *wn = Some(Box::new(worker_name));
132            }
133            InstanceType::Interface {
134                worker_name: wn, ..
135            } => {
136                *wn = Some(Box::new(worker_name));
137            }
138            InstanceType::PackageInterface {
139                worker_name: wn, ..
140            } => {
141                *wn = Some(Box::new(worker_name));
142            }
143            InstanceType::Resource {
144                worker_name: wn, ..
145            } => {
146                *wn = Some(Box::new(worker_name));
147            }
148        }
149    }
150
151    pub fn worker_mut(&mut self) -> Option<&mut Box<Expr>> {
152        match self {
153            InstanceType::Global { worker_name, .. } => worker_name.as_mut(),
154            InstanceType::Package { worker_name, .. } => worker_name.as_mut(),
155            InstanceType::Interface { worker_name, .. } => worker_name.as_mut(),
156            InstanceType::PackageInterface { worker_name, .. } => worker_name.as_mut(),
157            InstanceType::Resource { worker_name, .. } => worker_name.as_mut(),
158        }
159    }
160
161    pub fn worker(&self) -> Option<&Expr> {
162        match self {
163            InstanceType::Global { worker_name, .. } => worker_name.as_ref().map(|v| v.deref()),
164            InstanceType::Package { worker_name, .. } => worker_name.as_ref().map(|v| v.deref()),
165            InstanceType::Interface { worker_name, .. } => worker_name.as_ref().map(|v| v.deref()),
166            InstanceType::PackageInterface { worker_name, .. } => {
167                worker_name.as_ref().map(|v| v.deref())
168            }
169            InstanceType::Resource { worker_name, .. } => worker_name.as_ref().map(|v| v.deref()),
170        }
171    }
172
173    // Get InstanceType::Resource from the fully qualified resource constructor
174    // from an existing instance type
175    pub fn get_resource_instance_type(
176        &self,
177        fully_qualified_resource_constructor: FullyQualifiedResourceConstructor,
178        resource_args: Vec<Expr>,
179        worker_name: Option<Box<Expr>>,
180        analysed_resource_id: u64,
181        analysed_resource_mode: u8,
182    ) -> Result<InstanceType, String> {
183        let interface_name = fully_qualified_resource_constructor.interface_name.clone();
184        let package_name = fully_qualified_resource_constructor.package_name.clone();
185        let resource_constructor_name = fully_qualified_resource_constructor.resource_name.clone();
186
187        let mut tree = vec![];
188        for (component_info, function_type) in self.component_dependencies().dependencies.iter() {
189            let mut resource_method_dict = BTreeMap::new();
190
191            for (name, typ) in function_type.name_and_types.iter() {
192                if let FunctionName::ResourceMethod(resource_method) = name {
193                    if resource_method.resource_name == resource_constructor_name
194                        && resource_method.interface_name == interface_name
195                        && resource_method.package_name == package_name
196                    {
197                        resource_method_dict.insert(resource_method.clone(), typ.clone());
198                    }
199                }
200            }
201
202            tree.push((component_info.clone(), resource_method_dict));
203        }
204
205        if tree.len() == 1 {
206            let (component_dependency_key, resource_methods) = tree.pop().unwrap();
207
208            let resource_method_dict = ResourceMethodDictionary {
209                map: resource_methods,
210            };
211
212            Ok(InstanceType::Resource {
213                worker_name,
214                package_name,
215                interface_name,
216                resource_constructor: resource_constructor_name,
217                resource_args,
218                component_dependency_key,
219                resource_method_dictionary: resource_method_dict,
220                analysed_resource_id,
221                analysed_resource_mode,
222            })
223        } else if tree.is_empty() {
224            Err(format!(
225                "No components found have the resource constructor '{}'",
226                resource_constructor_name
227            ))
228        } else {
229            Err(format!(
230                "Multiple components found with the resource constructor '{}'. Please specify the type parameter",
231                resource_constructor_name
232            ))
233        }
234    }
235
236    pub fn interface_name(&self) -> Option<InterfaceName> {
237        match self {
238            InstanceType::Global { .. } => None,
239            InstanceType::Package { .. } => None,
240            InstanceType::Interface { interface_name, .. } => Some(interface_name.clone()),
241            InstanceType::PackageInterface { interface_name, .. } => Some(interface_name.clone()),
242            InstanceType::Resource { interface_name, .. } => interface_name.clone(),
243        }
244    }
245
246    pub fn package_name(&self) -> Option<PackageName> {
247        match self {
248            InstanceType::Global { .. } => None,
249            InstanceType::Package { package_name, .. } => Some(package_name.clone()),
250            InstanceType::Interface { .. } => None,
251            InstanceType::PackageInterface { package_name, .. } => Some(package_name.clone()),
252            InstanceType::Resource { package_name, .. } => package_name.clone(),
253        }
254    }
255
256    pub fn worker_name(&self) -> Option<Box<Expr>> {
257        match self {
258            InstanceType::Global { worker_name, .. } => worker_name.clone(),
259            InstanceType::Package { worker_name, .. } => worker_name.clone(),
260            InstanceType::Interface { worker_name, .. } => worker_name.clone(),
261            InstanceType::PackageInterface { worker_name, .. } => worker_name.clone(),
262            InstanceType::Resource { worker_name, .. } => worker_name.clone(),
263        }
264    }
265    pub fn get_function(
266        &self,
267        method_name: &str,
268        type_parameter: Option<TypeParameter>,
269    ) -> Result<(ComponentDependencyKey, Function), String> {
270        match type_parameter {
271            Some(tp) => match tp {
272                TypeParameter::Interface(iface) => {
273                    let component_dependency =
274                        self.component_dependencies().filter_by_interface(&iface)?;
275
276                    if component_dependency.size() == 1 {
277                        let (info, function_dictionary) =
278                            component_dependency.dependencies.first_key_value().unwrap();
279
280                        let functions = function_dictionary
281                            .name_and_types
282                            .iter()
283                            .filter(|(f, _)| f.name() == method_name)
284                            .collect::<Vec<_>>();
285
286                        if functions.is_empty() {
287                            return Err(format!(
288                                "Function '{}' not found in interface '{}'",
289                                method_name, iface
290                            ));
291                        }
292
293                        if functions.len() == 1 {
294                            let (fqfn, ftype) = &functions[0];
295                            Ok((
296                                info.clone(),
297                                Function {
298                                    function_name: fqfn.clone(),
299                                    function_type: ftype.clone(),
300                                },
301                            ))
302                        } else {
303                            search_function_in_instance(self, method_name, Some(info))
304                        }
305                    } else {
306                        Err(format!(
307                            "Interface '{}' found in multiple components",
308                            iface
309                        ))
310                    }
311                }
312
313                TypeParameter::PackageName(pkg) => {
314                    let component_dependency =
315                        self.component_dependencies().filter_by_package_name(&pkg)?;
316
317                    if component_dependency.size() == 1 {
318                        let (info, function_dictionary) =
319                            component_dependency.dependencies.first_key_value().unwrap();
320
321                        let packages = function_dictionary
322                            .name_and_types
323                            .iter()
324                            .filter(|(f, _)| f.package_name() == Some(pkg.clone()))
325                            .collect::<Vec<_>>();
326
327                        if packages.is_empty() {
328                            return Err(format!("package '{}' not found", pkg));
329                        }
330
331                        let functions = packages
332                            .into_iter()
333                            .filter(|(f, _)| f.name() == method_name)
334                            .collect::<Vec<_>>();
335
336                        if functions.is_empty() {
337                            return Err(format!(
338                                "function '{}' not found in package '{}'",
339                                method_name, pkg
340                            ));
341                        }
342
343                        if functions.len() == 1 {
344                            let (fqfn, ftype) = &functions[0];
345                            Ok((
346                                info.clone(),
347                                Function {
348                                    function_name: fqfn.clone(),
349                                    function_type: ftype.clone(),
350                                },
351                            ))
352                        } else {
353                            search_function_in_instance(self, method_name, Some(info))
354                        }
355                    } else {
356                        Err(format!(
357                            "package '{}' found in multiple components. Please specify the root package name instead",
358                            pkg
359                        ))
360                    }
361                }
362
363                TypeParameter::FullyQualifiedInterface(fq_iface) => {
364                    let component_dependency = self
365                        .component_dependencies()
366                        .filter_by_fully_qualified_interface(&fq_iface)?;
367
368                    if component_dependency.size() == 1 {
369                        let (info, function_dictionary) =
370                            component_dependency.dependencies.first_key_value().unwrap();
371
372                        let functions = function_dictionary
373                            .name_and_types
374                            .iter()
375                            .filter(|(f, _)| {
376                                f.package_name() == Some(fq_iface.package_name.clone())
377                                    && f.interface_name() == Some(fq_iface.interface_name.clone())
378                                    && f.name() == method_name
379                            })
380                            .collect::<Vec<_>>();
381
382                        if functions.is_empty() {
383                            return Err(format!(
384                                "function '{}' not found in interface '{}'",
385                                method_name, fq_iface
386                            ));
387                        }
388
389                        if functions.len() == 1 {
390                            let (fqfn, ftype) = &functions[0];
391                            Ok((
392                                info.clone(),
393                                Function {
394                                    function_name: fqfn.clone(),
395                                    function_type: ftype.clone(),
396                                },
397                            ))
398                        } else {
399                            search_function_in_instance(self, method_name, Some(info))
400                        }
401                    } else {
402                        Err(format!(
403                            "interface '{}' found in multiple components. Please specify the root package name instead",
404                            fq_iface
405                        ))
406                    }
407                }
408            },
409            None => search_function_in_instance(self, method_name, None),
410        }
411    }
412
413    // A flattened list of all resource methods
414    pub fn resource_method_dictionary(&self) -> FunctionDictionary {
415        let name_and_types = self
416            .component_dependencies()
417            .dependencies
418            .values()
419            .flat_map(|function_dictionary| {
420                function_dictionary
421                    .name_and_types
422                    .iter()
423                    .filter(|(f, _)| matches!(f, FunctionName::ResourceMethod(_)))
424                    .map(|(f, t)| (f.clone(), t.clone()))
425                    .collect::<Vec<_>>()
426            })
427            .collect();
428
429        FunctionDictionary { name_and_types }
430    }
431
432    pub fn function_dict_without_resource_methods(&self) -> FunctionDictionary {
433        let name_and_types = self
434            .component_dependencies()
435            .dependencies
436            .values()
437            .flat_map(|function_dictionary| {
438                function_dictionary
439                    .name_and_types
440                    .iter()
441                    .filter(|(f, _)| {
442                        !matches!(f, FunctionName::ResourceMethod(_))
443                            && !matches!(f, FunctionName::Variant(_))
444                            && !matches!(f, FunctionName::Enum(_))
445                    })
446                    .map(|(f, t)| (f.clone(), t.clone()))
447                    .collect::<Vec<_>>()
448            })
449            .collect();
450
451        FunctionDictionary { name_and_types }
452    }
453
454    pub fn component_dependencies(&self) -> ComponentDependencies {
455        match self {
456            InstanceType::Global {
457                component_dependency,
458                ..
459            } => component_dependency.clone(),
460            InstanceType::Package {
461                component_dependency,
462                ..
463            } => component_dependency.clone(),
464            InstanceType::Interface {
465                component_dependency,
466                ..
467            } => component_dependency.clone(),
468            InstanceType::PackageInterface {
469                component_dependency,
470                ..
471            } => component_dependency.clone(),
472            InstanceType::Resource {
473                resource_method_dictionary,
474                component_dependency_key,
475                ..
476            } => {
477                let function_dictionary = FunctionDictionary::from(resource_method_dictionary);
478                let mut dependencies = BTreeMap::new();
479                dependencies.insert(component_dependency_key.clone(), function_dictionary);
480
481                ComponentDependencies { dependencies }
482            }
483        }
484    }
485
486    pub fn from(
487        dependency: &ComponentDependencies,
488        worker_name: Option<&Expr>,
489        type_parameter: Option<TypeParameter>,
490    ) -> Result<InstanceType, String> {
491        match type_parameter {
492            None => Ok(InstanceType::Global {
493                worker_name: worker_name.cloned().map(Box::new),
494                component_dependency: dependency.clone(),
495            }),
496            Some(type_parameter) => match type_parameter {
497                TypeParameter::Interface(interface_name) => {
498                    let new_dependency = dependency.filter_by_interface(&interface_name)?;
499
500                    Ok(InstanceType::Interface {
501                        worker_name: worker_name.cloned().map(Box::new),
502                        interface_name,
503                        component_dependency: new_dependency,
504                    })
505                }
506                TypeParameter::PackageName(package_name) => {
507                    let new_dependency = dependency.filter_by_package_name(&package_name)?;
508
509                    Ok(InstanceType::Package {
510                        worker_name: worker_name.cloned().map(Box::new),
511                        package_name,
512                        component_dependency: new_dependency,
513                    })
514                }
515                TypeParameter::FullyQualifiedInterface(fqi) => {
516                    let component_dependency =
517                        dependency.filter_by_fully_qualified_interface(&fqi)?;
518
519                    Ok(InstanceType::PackageInterface {
520                        worker_name: worker_name.cloned().map(Box::new),
521                        package_name: fqi.package_name,
522                        interface_name: fqi.interface_name,
523                        component_dependency,
524                    })
525                }
526            },
527        }
528    }
529}
530
531#[derive(Debug, Clone)]
532pub struct Function {
533    pub function_name: FunctionName,
534    pub function_type: FunctionType,
535}
536
537fn search_function_in_instance(
538    instance: &InstanceType,
539    function_name: &str,
540    component_info: Option<&ComponentDependencyKey>,
541) -> Result<(ComponentDependencyKey, Function), String> {
542    match component_info {
543        Some(component_info) => {
544            let dependencies = instance.component_dependencies();
545
546            let function_dictionary =
547                dependencies
548                    .dependencies
549                    .get(component_info)
550                    .ok_or(format!(
551                        "component '{}' not found in dependencies",
552                        component_info
553                    ))?;
554
555            let functions = function_dictionary
556                .name_and_types
557                .iter()
558                .filter(|(f, _)| f.name() == function_name)
559                .collect::<Vec<_>>();
560
561            if functions.is_empty() {
562                return Err(format!(
563                    "function '{}' not found in component '{}'",
564                    function_name, component_info
565                ));
566            }
567
568            let mut package_map: HashMap<Option<PackageName>, HashSet<Option<InterfaceName>>> =
569                HashMap::new();
570
571            for (fqfn, _) in &functions {
572                package_map
573                    .entry(fqfn.package_name())
574                    .or_default()
575                    .insert(fqfn.interface_name());
576            }
577
578            match package_map.len() {
579                1 => {
580                    let interfaces = package_map.values().flatten().cloned().collect();
581                    let function =
582                        search_function_in_single_package(interfaces, functions, function_name)?;
583
584                    Ok((component_info.clone(), function))
585                }
586                _ => {
587                    let function =
588                        search_function_in_multiple_packages(function_name, package_map)?;
589                    Ok((component_info.clone(), function))
590                }
591            }
592        }
593        None => {
594            let mut component_info_functions = vec![];
595
596            for (info, function_dictionary) in instance.component_dependencies().dependencies.iter()
597            {
598                let functions = function_dictionary
599                    .name_and_types
600                    .iter()
601                    .filter(|(f, _)| f.name() == function_name)
602                    .collect::<Vec<_>>();
603
604                if functions.is_empty() {
605                    continue;
606                }
607
608                let mut package_map: HashMap<Option<PackageName>, HashSet<Option<InterfaceName>>> =
609                    HashMap::new();
610
611                for (fqfn, _) in &functions {
612                    package_map
613                        .entry(fqfn.package_name())
614                        .or_default()
615                        .insert(fqfn.interface_name());
616                }
617
618                match package_map.len() {
619                    1 => {
620                        let interfaces = package_map.values().flatten().cloned().collect();
621                        let function = search_function_in_single_package(
622                            interfaces,
623                            functions,
624                            function_name,
625                        )?;
626
627                        component_info_functions.push((info.clone(), function));
628                    }
629                    _ => {
630                        let function =
631                            search_function_in_multiple_packages(function_name, package_map)?;
632                        component_info_functions.push((info.clone(), function));
633                    }
634                }
635            }
636
637            if component_info_functions.len() == 1 {
638                let (info, function) = &component_info_functions[0];
639                Ok((info.clone(), function.clone()))
640            } else if component_info_functions.is_empty() {
641                Err(format!("function '{}' not found", function_name))
642            } else {
643                Err(format!(
644                    "function '{}' found in multiple components. Please specify the type parameter",
645                    function_name
646                ))
647            }
648        }
649    }
650}
651
652fn search_function_in_single_package(
653    interfaces: HashSet<Option<InterfaceName>>,
654    functions: Vec<&(FunctionName, FunctionType)>,
655    function_name: &str,
656) -> Result<Function, String> {
657    if interfaces.len() == 1 {
658        let (fqfn, ftype) = &functions[0];
659        Ok(Function {
660            function_name: fqfn.clone(),
661            function_type: ftype.clone(),
662        })
663    } else {
664        let mut interfaces = interfaces
665            .into_iter()
666            .filter_map(|iface| iface.map(|i| i.name))
667            .collect::<Vec<_>>();
668
669        interfaces.sort();
670
671        // Multiple interfaces in the same package -> Ask for an interface name
672        Err(format!(
673            "multiple interfaces contain function '{}'. specify an interface name as type parameter from: {}",
674            function_name,
675            interfaces
676                .join(", ")
677        ))
678    }
679}
680
681fn search_function_in_multiple_packages(
682    function_name: &str,
683    package_map: HashMap<Option<PackageName>, HashSet<Option<InterfaceName>>>,
684) -> Result<Function, String> {
685    let mut error_msg = format!(
686        "function '{}' exists in multiple packages. specify a package name as type parameter from: ",
687        function_name
688    );
689
690    let mut package_interface_list = package_map
691        .into_iter()
692        .filter_map(|(pkg, interfaces)| {
693            pkg.map(|p| {
694                let mut interface_list = interfaces
695                    .into_iter()
696                    .filter_map(|iface| iface.map(|i| i.name))
697                    .collect::<Vec<_>>();
698
699                interface_list.sort();
700
701                if interface_list.is_empty() {
702                    format!("{}", p)
703                } else {
704                    format!("{} (interfaces: {})", p, interface_list.join(", "))
705                }
706            })
707        })
708        .collect::<Vec<_>>();
709
710    package_interface_list.sort();
711
712    error_msg.push_str(&package_interface_list.join(", "));
713    Err(error_msg)
714}
715
716#[cfg(feature = "protobuf")]
717mod protobuf {
718    use crate::{
719        FullyQualifiedFunctionName, FullyQualifiedResourceConstructor,
720        FullyQualifiedResourceMethod, InterfaceName, PackageName,
721    };
722    use golem_api_grpc::proto::golem::rib::FullyQualifiedFunctionName as ProtoFullyQualifiedFunctionName;
723    use golem_api_grpc::proto::golem::rib::FullyQualifiedResourceConstructor as ProtoFullyQualifiedResourceConstructor;
724    use golem_api_grpc::proto::golem::rib::FullyQualifiedResourceMethod as ProtoFullyQualifiedResourceMethod;
725    use golem_api_grpc::proto::golem::rib::InterfaceName as ProtoInterfaceName;
726    use golem_api_grpc::proto::golem::rib::PackageName as ProtoPackageName;
727
728    impl TryFrom<ProtoPackageName> for PackageName {
729        type Error = String;
730
731        fn try_from(proto: ProtoPackageName) -> Result<Self, Self::Error> {
732            Ok(PackageName {
733                namespace: proto.namespace,
734                package_name: proto.package_name,
735                version: proto.version,
736            })
737        }
738    }
739
740    impl TryFrom<ProtoInterfaceName> for InterfaceName {
741        type Error = String;
742
743        fn try_from(value: ProtoInterfaceName) -> Result<Self, Self::Error> {
744            Ok(InterfaceName {
745                name: value.name,
746                version: value.version,
747            })
748        }
749    }
750
751    impl TryFrom<ProtoFullyQualifiedFunctionName> for FullyQualifiedFunctionName {
752        type Error = String;
753
754        fn try_from(proto: ProtoFullyQualifiedFunctionName) -> Result<Self, Self::Error> {
755            Ok(FullyQualifiedFunctionName {
756                package_name: proto.package_name.map(TryFrom::try_from).transpose()?,
757                interface_name: proto.interface_name.map(TryFrom::try_from).transpose()?,
758                function_name: proto.function_name,
759            })
760        }
761    }
762
763    impl From<FullyQualifiedFunctionName> for ProtoFullyQualifiedFunctionName {
764        fn from(value: FullyQualifiedFunctionName) -> Self {
765            ProtoFullyQualifiedFunctionName {
766                package_name: value.package_name.map(ProtoPackageName::from),
767                interface_name: value.interface_name.map(ProtoInterfaceName::from),
768                function_name: value.function_name,
769            }
770        }
771    }
772
773    impl TryFrom<ProtoFullyQualifiedResourceMethod> for FullyQualifiedResourceMethod {
774        type Error = String;
775
776        fn try_from(proto: ProtoFullyQualifiedResourceMethod) -> Result<Self, Self::Error> {
777            Ok(FullyQualifiedResourceMethod {
778                resource_name: proto.resource_name,
779                method_name: proto.method_name,
780                package_name: proto.package_name.map(TryFrom::try_from).transpose()?,
781                interface_name: proto.interface_name.map(TryFrom::try_from).transpose()?,
782            })
783        }
784    }
785
786    impl From<FullyQualifiedResourceMethod> for ProtoFullyQualifiedResourceMethod {
787        fn from(value: FullyQualifiedResourceMethod) -> Self {
788            ProtoFullyQualifiedResourceMethod {
789                resource_name: value.resource_name,
790                method_name: value.method_name,
791                package_name: value.package_name.map(ProtoPackageName::from),
792                interface_name: value.interface_name.map(ProtoInterfaceName::from),
793            }
794        }
795    }
796
797    impl TryFrom<ProtoFullyQualifiedResourceConstructor> for FullyQualifiedResourceConstructor {
798        type Error = String;
799
800        fn try_from(proto: ProtoFullyQualifiedResourceConstructor) -> Result<Self, Self::Error> {
801            Ok(FullyQualifiedResourceConstructor {
802                package_name: proto.package_name.map(TryFrom::try_from).transpose()?,
803                interface_name: proto.interface_name.map(TryFrom::try_from).transpose()?,
804                resource_name: proto.resource_name,
805            })
806        }
807    }
808}
809
810impl TryFrom<ProtoFunctionType> for FunctionType {
811    type Error = String;
812
813    fn try_from(proto: ProtoFunctionType) -> Result<Self, Self::Error> {
814        let mut parameter_types = Vec::new();
815        for param in proto.parameter_types {
816            parameter_types.push(InferredType::from(&AnalysedType::try_from(&param)?));
817        }
818
819        let return_type = proto
820            .return_type
821            .as_ref()
822            .map(|ret| AnalysedType::try_from(ret).map(|ret| InferredType::from(&ret)))
823            .transpose()?;
824
825        Ok(Self {
826            parameter_types,
827            return_type,
828        })
829    }
830}
831
832impl From<PackageName> for ProtoPackageName {
833    fn from(value: PackageName) -> Self {
834        ProtoPackageName {
835            namespace: value.namespace,
836            package_name: value.package_name,
837            version: value.version,
838        }
839    }
840}
841
842impl From<InterfaceName> for ProtoInterfaceName {
843    fn from(value: InterfaceName) -> Self {
844        ProtoInterfaceName {
845            name: value.name,
846            version: value.version,
847        }
848    }
849}
850
851impl From<FullyQualifiedResourceConstructor> for ProtoFullyQualifiedResourceConstructor {
852    fn from(value: FullyQualifiedResourceConstructor) -> Self {
853        ProtoFullyQualifiedResourceConstructor {
854            package_name: value.package_name.map(ProtoPackageName::from),
855            interface_name: value.interface_name.map(ProtoInterfaceName::from),
856            resource_name: value.resource_name,
857        }
858    }
859}