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