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