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 '{resource_constructor_name}'"
226            ))
227        } else {
228            Err(format!(
229                "Multiple components found with the resource constructor '{resource_constructor_name}'. Please specify the type parameter"
230            ))
231        }
232    }
233
234    pub fn interface_name(&self) -> Option<InterfaceName> {
235        match self {
236            InstanceType::Global { .. } => None,
237            InstanceType::Package { .. } => None,
238            InstanceType::Interface { interface_name, .. } => Some(interface_name.clone()),
239            InstanceType::PackageInterface { interface_name, .. } => Some(interface_name.clone()),
240            InstanceType::Resource { interface_name, .. } => interface_name.clone(),
241        }
242    }
243
244    pub fn package_name(&self) -> Option<PackageName> {
245        match self {
246            InstanceType::Global { .. } => None,
247            InstanceType::Package { package_name, .. } => Some(package_name.clone()),
248            InstanceType::Interface { .. } => None,
249            InstanceType::PackageInterface { package_name, .. } => Some(package_name.clone()),
250            InstanceType::Resource { package_name, .. } => package_name.clone(),
251        }
252    }
253
254    pub fn worker_name(&self) -> Option<Box<Expr>> {
255        match self {
256            InstanceType::Global { worker_name, .. } => worker_name.clone(),
257            InstanceType::Package { worker_name, .. } => worker_name.clone(),
258            InstanceType::Interface { worker_name, .. } => worker_name.clone(),
259            InstanceType::PackageInterface { worker_name, .. } => worker_name.clone(),
260            InstanceType::Resource { worker_name, .. } => worker_name.clone(),
261        }
262    }
263    pub fn get_function(
264        &self,
265        method_name: &str,
266        type_parameter: Option<TypeParameter>,
267    ) -> Result<(ComponentDependencyKey, Function), String> {
268        match type_parameter {
269            Some(tp) => match tp {
270                TypeParameter::Interface(iface) => {
271                    let component_dependency =
272                        self.component_dependencies().filter_by_interface(&iface)?;
273
274                    if component_dependency.size() == 1 {
275                        let (info, function_dictionary) =
276                            component_dependency.dependencies.first_key_value().unwrap();
277
278                        let functions = function_dictionary
279                            .name_and_types
280                            .iter()
281                            .filter(|(f, _)| f.name() == method_name)
282                            .collect::<Vec<_>>();
283
284                        if functions.is_empty() {
285                            return Err(format!(
286                                "Function '{method_name}' not found in interface '{iface}'"
287                            ));
288                        }
289
290                        if functions.len() == 1 {
291                            let (fqfn, ftype) = &functions[0];
292                            Ok((
293                                info.clone(),
294                                Function {
295                                    function_name: fqfn.clone(),
296                                    function_type: ftype.clone(),
297                                },
298                            ))
299                        } else {
300                            search_function_in_instance(self, method_name, Some(info))
301                        }
302                    } else {
303                        Err(format!("Interface '{iface}' found in multiple components"))
304                    }
305                }
306
307                TypeParameter::PackageName(pkg) => {
308                    let component_dependency =
309                        self.component_dependencies().filter_by_package_name(&pkg)?;
310
311                    if component_dependency.size() == 1 {
312                        let (info, function_dictionary) =
313                            component_dependency.dependencies.first_key_value().unwrap();
314
315                        let packages = function_dictionary
316                            .name_and_types
317                            .iter()
318                            .filter(|(f, _)| f.package_name() == Some(pkg.clone()))
319                            .collect::<Vec<_>>();
320
321                        if packages.is_empty() {
322                            return Err(format!("package '{pkg}' not found"));
323                        }
324
325                        let functions = packages
326                            .into_iter()
327                            .filter(|(f, _)| f.name() == method_name)
328                            .collect::<Vec<_>>();
329
330                        if functions.is_empty() {
331                            return Err(format!(
332                                "function '{method_name}' not found in package '{pkg}'"
333                            ));
334                        }
335
336                        if functions.len() == 1 {
337                            let (fqfn, ftype) = &functions[0];
338                            Ok((
339                                info.clone(),
340                                Function {
341                                    function_name: fqfn.clone(),
342                                    function_type: ftype.clone(),
343                                },
344                            ))
345                        } else {
346                            search_function_in_instance(self, method_name, Some(info))
347                        }
348                    } else {
349                        Err(format!(
350                            "package '{pkg}' found in multiple components. Please specify the root package name instead"
351                        ))
352                    }
353                }
354
355                TypeParameter::FullyQualifiedInterface(fq_iface) => {
356                    let component_dependency = self
357                        .component_dependencies()
358                        .filter_by_fully_qualified_interface(&fq_iface)?;
359
360                    if component_dependency.size() == 1 {
361                        let (info, function_dictionary) =
362                            component_dependency.dependencies.first_key_value().unwrap();
363
364                        let functions = function_dictionary
365                            .name_and_types
366                            .iter()
367                            .filter(|(f, _)| {
368                                f.package_name() == Some(fq_iface.package_name.clone())
369                                    && f.interface_name() == Some(fq_iface.interface_name.clone())
370                                    && f.name() == method_name
371                            })
372                            .collect::<Vec<_>>();
373
374                        if functions.is_empty() {
375                            return Err(format!(
376                                "function '{method_name}' not found in interface '{fq_iface}'"
377                            ));
378                        }
379
380                        if functions.len() == 1 {
381                            let (fqfn, ftype) = &functions[0];
382                            Ok((
383                                info.clone(),
384                                Function {
385                                    function_name: fqfn.clone(),
386                                    function_type: ftype.clone(),
387                                },
388                            ))
389                        } else {
390                            search_function_in_instance(self, method_name, Some(info))
391                        }
392                    } else {
393                        Err(format!(
394                            "interface '{fq_iface}' found in multiple components. Please specify the root package name instead"
395                        ))
396                    }
397                }
398            },
399            None => search_function_in_instance(self, method_name, None),
400        }
401    }
402
403    // A flattened list of all resource methods
404    pub fn resource_method_dictionary(&self) -> FunctionDictionary {
405        let name_and_types = self
406            .component_dependencies()
407            .dependencies
408            .values()
409            .flat_map(|function_dictionary| {
410                function_dictionary
411                    .name_and_types
412                    .iter()
413                    .filter(|(f, _)| matches!(f, FunctionName::ResourceMethod(_)))
414                    .map(|(f, t)| (f.clone(), t.clone()))
415                    .collect::<Vec<_>>()
416            })
417            .collect();
418
419        FunctionDictionary { name_and_types }
420    }
421
422    pub fn function_dict_without_resource_methods(&self) -> FunctionDictionary {
423        let name_and_types = self
424            .component_dependencies()
425            .dependencies
426            .values()
427            .flat_map(|function_dictionary| {
428                function_dictionary
429                    .name_and_types
430                    .iter()
431                    .filter(|(f, _)| {
432                        !matches!(f, FunctionName::ResourceMethod(_))
433                            && !matches!(f, FunctionName::Variant(_))
434                            && !matches!(f, FunctionName::Enum(_))
435                    })
436                    .map(|(f, t)| (f.clone(), t.clone()))
437                    .collect::<Vec<_>>()
438            })
439            .collect();
440
441        FunctionDictionary { name_and_types }
442    }
443
444    pub fn component_dependencies(&self) -> ComponentDependencies {
445        match self {
446            InstanceType::Global {
447                component_dependency,
448                ..
449            } => component_dependency.clone(),
450            InstanceType::Package {
451                component_dependency,
452                ..
453            } => component_dependency.clone(),
454            InstanceType::Interface {
455                component_dependency,
456                ..
457            } => component_dependency.clone(),
458            InstanceType::PackageInterface {
459                component_dependency,
460                ..
461            } => component_dependency.clone(),
462            InstanceType::Resource {
463                resource_method_dictionary,
464                component_dependency_key,
465                ..
466            } => {
467                let function_dictionary = FunctionDictionary::from(resource_method_dictionary);
468                let mut dependencies = BTreeMap::new();
469                dependencies.insert(component_dependency_key.clone(), function_dictionary);
470
471                ComponentDependencies { dependencies }
472            }
473        }
474    }
475
476    pub fn from(
477        dependency: &ComponentDependencies,
478        worker_name: Option<&Expr>,
479        type_parameter: Option<TypeParameter>,
480    ) -> Result<InstanceType, String> {
481        match type_parameter {
482            None => Ok(InstanceType::Global {
483                worker_name: worker_name.cloned().map(Box::new),
484                component_dependency: dependency.clone(),
485            }),
486            Some(type_parameter) => match type_parameter {
487                TypeParameter::Interface(interface_name) => {
488                    let new_dependency = dependency.filter_by_interface(&interface_name)?;
489
490                    Ok(InstanceType::Interface {
491                        worker_name: worker_name.cloned().map(Box::new),
492                        interface_name,
493                        component_dependency: new_dependency,
494                    })
495                }
496                TypeParameter::PackageName(package_name) => {
497                    let new_dependency = dependency.filter_by_package_name(&package_name)?;
498
499                    Ok(InstanceType::Package {
500                        worker_name: worker_name.cloned().map(Box::new),
501                        package_name,
502                        component_dependency: new_dependency,
503                    })
504                }
505                TypeParameter::FullyQualifiedInterface(fqi) => {
506                    let component_dependency =
507                        dependency.filter_by_fully_qualified_interface(&fqi)?;
508
509                    Ok(InstanceType::PackageInterface {
510                        worker_name: worker_name.cloned().map(Box::new),
511                        package_name: fqi.package_name,
512                        interface_name: fqi.interface_name,
513                        component_dependency,
514                    })
515                }
516            },
517        }
518    }
519}
520
521#[derive(Debug, Clone)]
522pub struct Function {
523    pub function_name: FunctionName,
524    pub function_type: FunctionType,
525}
526
527fn search_function_in_instance(
528    instance: &InstanceType,
529    function_name: &str,
530    component_info: Option<&ComponentDependencyKey>,
531) -> Result<(ComponentDependencyKey, Function), String> {
532    match component_info {
533        Some(component_info) => {
534            let dependencies = instance.component_dependencies();
535
536            let function_dictionary =
537                dependencies
538                    .dependencies
539                    .get(component_info)
540                    .ok_or(format!(
541                        "component '{component_info}' not found in dependencies"
542                    ))?;
543
544            let functions = function_dictionary
545                .name_and_types
546                .iter()
547                .filter(|(f, _)| f.name() == function_name)
548                .collect::<Vec<_>>();
549
550            if functions.is_empty() {
551                return Err(format!(
552                    "function '{function_name}' not found in component '{component_info}'"
553                ));
554            }
555
556            let mut package_map: HashMap<Option<PackageName>, HashSet<Option<InterfaceName>>> =
557                HashMap::new();
558
559            for (fqfn, _) in &functions {
560                package_map
561                    .entry(fqfn.package_name())
562                    .or_default()
563                    .insert(fqfn.interface_name());
564            }
565
566            match package_map.len() {
567                1 => {
568                    let interfaces = package_map.values().flatten().cloned().collect();
569                    let function =
570                        search_function_in_single_package(interfaces, functions, function_name)?;
571
572                    Ok((component_info.clone(), function))
573                }
574                _ => {
575                    let function =
576                        search_function_in_multiple_packages(function_name, package_map)?;
577                    Ok((component_info.clone(), function))
578                }
579            }
580        }
581        None => {
582            let mut component_info_functions = vec![];
583
584            for (info, function_dictionary) in instance.component_dependencies().dependencies.iter()
585            {
586                let functions = function_dictionary
587                    .name_and_types
588                    .iter()
589                    .filter(|(f, _)| f.name() == function_name)
590                    .collect::<Vec<_>>();
591
592                if functions.is_empty() {
593                    continue;
594                }
595
596                let mut package_map: HashMap<Option<PackageName>, HashSet<Option<InterfaceName>>> =
597                    HashMap::new();
598
599                for (fqfn, _) in &functions {
600                    package_map
601                        .entry(fqfn.package_name())
602                        .or_default()
603                        .insert(fqfn.interface_name());
604                }
605
606                match package_map.len() {
607                    1 => {
608                        let interfaces = package_map.values().flatten().cloned().collect();
609                        let function = search_function_in_single_package(
610                            interfaces,
611                            functions,
612                            function_name,
613                        )?;
614
615                        component_info_functions.push((info.clone(), function));
616                    }
617                    _ => {
618                        let function =
619                            search_function_in_multiple_packages(function_name, package_map)?;
620                        component_info_functions.push((info.clone(), function));
621                    }
622                }
623            }
624
625            if component_info_functions.len() == 1 {
626                let (info, function) = &component_info_functions[0];
627                Ok((info.clone(), function.clone()))
628            } else if component_info_functions.is_empty() {
629                Err(format!("function '{function_name}' not found"))
630            } else {
631                Err(format!(
632                    "function '{function_name}' found in multiple components. Please specify the type parameter"
633                ))
634            }
635        }
636    }
637}
638
639fn search_function_in_single_package(
640    interfaces: HashSet<Option<InterfaceName>>,
641    functions: Vec<&(FunctionName, FunctionType)>,
642    function_name: &str,
643) -> Result<Function, String> {
644    if interfaces.len() == 1 {
645        let (fqfn, ftype) = &functions[0];
646        Ok(Function {
647            function_name: fqfn.clone(),
648            function_type: ftype.clone(),
649        })
650    } else {
651        let mut interfaces = interfaces
652            .into_iter()
653            .filter_map(|iface| iface.map(|i| i.name))
654            .collect::<Vec<_>>();
655
656        interfaces.sort();
657
658        // Multiple interfaces in the same package -> Ask for an interface name
659        Err(format!(
660            "multiple interfaces contain function '{}'. specify an interface name as type parameter from: {}",
661            function_name,
662            interfaces
663                .join(", ")
664        ))
665    }
666}
667
668fn search_function_in_multiple_packages(
669    function_name: &str,
670    package_map: HashMap<Option<PackageName>, HashSet<Option<InterfaceName>>>,
671) -> Result<Function, String> {
672    let mut error_msg = format!(
673        "function '{function_name}' exists in multiple packages. specify a package name as type parameter from: "
674    );
675
676    let mut package_interface_list = package_map
677        .into_iter()
678        .filter_map(|(pkg, interfaces)| {
679            pkg.map(|p| {
680                let mut interface_list = interfaces
681                    .into_iter()
682                    .filter_map(|iface| iface.map(|i| i.name))
683                    .collect::<Vec<_>>();
684
685                interface_list.sort();
686
687                if interface_list.is_empty() {
688                    format!("{p}")
689                } else {
690                    format!("{} (interfaces: {})", p, interface_list.join(", "))
691                }
692            })
693        })
694        .collect::<Vec<_>>();
695
696    package_interface_list.sort();
697
698    error_msg.push_str(&package_interface_list.join(", "));
699    Err(error_msg)
700}
701
702#[cfg(feature = "protobuf")]
703mod protobuf {
704    use crate::{
705        FullyQualifiedFunctionName, FullyQualifiedResourceConstructor,
706        FullyQualifiedResourceMethod, InterfaceName, PackageName,
707    };
708    use golem_api_grpc::proto::golem::rib::FullyQualifiedFunctionName as ProtoFullyQualifiedFunctionName;
709    use golem_api_grpc::proto::golem::rib::FullyQualifiedResourceConstructor as ProtoFullyQualifiedResourceConstructor;
710    use golem_api_grpc::proto::golem::rib::FullyQualifiedResourceMethod as ProtoFullyQualifiedResourceMethod;
711    use golem_api_grpc::proto::golem::rib::InterfaceName as ProtoInterfaceName;
712    use golem_api_grpc::proto::golem::rib::PackageName as ProtoPackageName;
713
714    impl TryFrom<ProtoPackageName> for PackageName {
715        type Error = String;
716
717        fn try_from(proto: ProtoPackageName) -> Result<Self, Self::Error> {
718            Ok(PackageName {
719                namespace: proto.namespace,
720                package_name: proto.package_name,
721                version: proto.version,
722            })
723        }
724    }
725
726    impl TryFrom<ProtoInterfaceName> for InterfaceName {
727        type Error = String;
728
729        fn try_from(value: ProtoInterfaceName) -> Result<Self, Self::Error> {
730            Ok(InterfaceName {
731                name: value.name,
732                version: value.version,
733            })
734        }
735    }
736
737    impl TryFrom<ProtoFullyQualifiedFunctionName> for FullyQualifiedFunctionName {
738        type Error = String;
739
740        fn try_from(proto: ProtoFullyQualifiedFunctionName) -> Result<Self, Self::Error> {
741            Ok(FullyQualifiedFunctionName {
742                package_name: proto.package_name.map(TryFrom::try_from).transpose()?,
743                interface_name: proto.interface_name.map(TryFrom::try_from).transpose()?,
744                function_name: proto.function_name,
745            })
746        }
747    }
748
749    impl From<FullyQualifiedFunctionName> for ProtoFullyQualifiedFunctionName {
750        fn from(value: FullyQualifiedFunctionName) -> Self {
751            ProtoFullyQualifiedFunctionName {
752                package_name: value.package_name.map(ProtoPackageName::from),
753                interface_name: value.interface_name.map(ProtoInterfaceName::from),
754                function_name: value.function_name,
755            }
756        }
757    }
758
759    impl TryFrom<ProtoFullyQualifiedResourceMethod> for FullyQualifiedResourceMethod {
760        type Error = String;
761
762        fn try_from(proto: ProtoFullyQualifiedResourceMethod) -> Result<Self, Self::Error> {
763            Ok(FullyQualifiedResourceMethod {
764                resource_name: proto.resource_name,
765                method_name: proto.method_name,
766                package_name: proto.package_name.map(TryFrom::try_from).transpose()?,
767                interface_name: proto.interface_name.map(TryFrom::try_from).transpose()?,
768            })
769        }
770    }
771
772    impl From<FullyQualifiedResourceMethod> for ProtoFullyQualifiedResourceMethod {
773        fn from(value: FullyQualifiedResourceMethod) -> Self {
774            ProtoFullyQualifiedResourceMethod {
775                resource_name: value.resource_name,
776                method_name: value.method_name,
777                package_name: value.package_name.map(ProtoPackageName::from),
778                interface_name: value.interface_name.map(ProtoInterfaceName::from),
779            }
780        }
781    }
782
783    impl TryFrom<ProtoFullyQualifiedResourceConstructor> for FullyQualifiedResourceConstructor {
784        type Error = String;
785
786        fn try_from(proto: ProtoFullyQualifiedResourceConstructor) -> Result<Self, Self::Error> {
787            Ok(FullyQualifiedResourceConstructor {
788                package_name: proto.package_name.map(TryFrom::try_from).transpose()?,
789                interface_name: proto.interface_name.map(TryFrom::try_from).transpose()?,
790                resource_name: proto.resource_name,
791            })
792        }
793    }
794}
795
796impl TryFrom<ProtoFunctionType> for FunctionType {
797    type Error = String;
798
799    fn try_from(proto: ProtoFunctionType) -> Result<Self, Self::Error> {
800        let mut parameter_types = Vec::new();
801        for param in proto.parameter_types {
802            parameter_types.push(InferredType::from(&AnalysedType::try_from(&param)?));
803        }
804
805        let return_type = proto
806            .return_type
807            .as_ref()
808            .map(|ret| AnalysedType::try_from(ret).map(|ret| InferredType::from(&ret)))
809            .transpose()?;
810
811        Ok(Self {
812            parameter_types,
813            return_type,
814        })
815    }
816}
817
818impl From<PackageName> for ProtoPackageName {
819    fn from(value: PackageName) -> Self {
820        ProtoPackageName {
821            namespace: value.namespace,
822            package_name: value.package_name,
823            version: value.version,
824        }
825    }
826}
827
828impl From<InterfaceName> for ProtoInterfaceName {
829    fn from(value: InterfaceName) -> Self {
830        ProtoInterfaceName {
831            name: value.name,
832            version: value.version,
833        }
834    }
835}
836
837impl From<FullyQualifiedResourceConstructor> for ProtoFullyQualifiedResourceConstructor {
838    fn from(value: FullyQualifiedResourceConstructor) -> Self {
839        ProtoFullyQualifiedResourceConstructor {
840            package_name: value.package_name.map(ProtoPackageName::from),
841            interface_name: value.interface_name.map(ProtoInterfaceName::from),
842            resource_name: value.resource_name,
843        }
844    }
845}