1use crate::parser::{PackageName, TypeParameter};
16use crate::type_parameter::InterfaceName;
17use crate::{
18 CallType, DynamicParsedFunctionName, DynamicParsedFunctionReference, FunctionTypeRegistry,
19 InferredType, ParsedFunctionSite, RegistryKey, RegistryValue, SemVer,
20};
21use golem_wasm_ast::analysis::{AnalysedExport, AnalysedType, TypeEnum, TypeVariant};
22use std::collections::BTreeMap;
23use std::convert::TryFrom;
24use std::fmt::{Debug, Display, Formatter};
25
26#[derive(Debug, Hash, Clone, Eq, PartialEq, Ord, PartialOrd, Default)]
32pub struct FunctionDictionary {
33 pub name_and_types: Vec<(FunctionName, FunctionType)>,
34}
35
36impl FunctionDictionary {
37 pub fn get(&self, function_name: &FunctionName) -> Option<&FunctionType> {
38 self.name_and_types.iter().find_map(|(name, ftype)| {
39 if name == function_name {
40 Some(ftype)
41 } else {
42 None
43 }
44 })
45 }
46
47 pub fn get_all_variants(&self) -> Vec<TypeVariant> {
48 self.name_and_types
49 .iter()
50 .filter_map(|(_, ftype)| ftype.as_type_variant())
51 .collect()
52 }
53
54 pub fn get_all_enums(&self) -> Vec<TypeEnum> {
55 self.name_and_types
56 .iter()
57 .filter_map(|(_, ftype)| ftype.as_type_enum())
58 .collect()
59 }
60
61 pub fn get_enum_info(&self, identifier_name: &str) -> Option<TypeEnum> {
62 self.name_and_types.iter().find_map(|(f, ftype)| match f {
63 FunctionName::Enum(name) => {
64 if name == identifier_name {
65 ftype.as_type_enum()
66 } else {
67 None
68 }
69 }
70 _ => None,
71 })
72 }
73 pub fn get_variant_info(&self, identifier_name: &str) -> Vec<TypeVariant> {
74 self.name_and_types
75 .iter()
76 .filter_map(|(f, ftype)| match f {
77 FunctionName::Variant(name) => {
78 if name == identifier_name {
79 ftype.as_type_variant()
80 } else {
81 None
82 }
83 }
84 _ => None,
85 })
86 .collect::<Vec<_>>()
87 }
88
89 pub fn function_names(&self) -> Vec<String> {
90 self.name_and_types
91 .iter()
92 .map(|(f, _)| f.name())
93 .collect::<Vec<_>>()
94 }
95}
96
97#[derive(Debug, Hash, Clone, Eq, PartialEq, PartialOrd, Ord)]
104pub struct ResourceMethodDictionary {
105 pub map: BTreeMap<FullyQualifiedResourceMethod, FunctionType>,
106}
107
108impl From<&ResourceMethodDictionary> for FunctionDictionary {
109 fn from(value: &ResourceMethodDictionary) -> Self {
110 FunctionDictionary {
111 name_and_types: value
112 .map
113 .iter()
114 .map(|(key, value)| (FunctionName::ResourceMethod(key.clone()), value.clone()))
115 .collect(),
116 }
117 }
118}
119
120impl FunctionDictionary {
121 pub fn from_exports(exports: &[AnalysedExport]) -> Result<FunctionDictionary, String> {
122 let registry = FunctionTypeRegistry::from_export_metadata(exports);
123 Self::from_function_type_registry(®istry)
124 }
125
126 pub fn from_function_type_registry(
127 registry: &FunctionTypeRegistry,
128 ) -> Result<FunctionDictionary, String> {
129 let mut map = vec![];
130
131 for (key, value) in registry.types.iter() {
132 match value {
133 RegistryValue::Function {
134 parameter_types,
135 return_type,
136 } => match key {
137 RegistryKey::FunctionName(function_name) => {
138 let function_name = resolve_function_name(None, None, function_name)?;
139
140 map.push((
141 function_name,
142 FunctionType {
143 parameter_types: parameter_types.iter().map(|x| x.into()).collect(),
144 return_type: return_type.as_ref().map(|x| x.into()),
145 },
146 ));
147 }
148
149 RegistryKey::FunctionNameWithInterface {
150 interface_name,
151 function_name,
152 } => {
153 let type_parameter = TypeParameter::from_text(interface_name.as_str())?;
154
155 let interface_name = type_parameter.get_interface_name();
156 let package_name = type_parameter.get_package_name();
157
158 let function_name =
159 resolve_function_name(package_name, interface_name, function_name)?;
160
161 map.push((
162 function_name,
163 FunctionType {
164 parameter_types: parameter_types.iter().map(|x| x.into()).collect(),
165 return_type: return_type.as_ref().map(|x| x.into()),
166 },
167 ));
168 }
169 },
170
171 RegistryValue::Variant {
172 parameter_types,
173 variant_type,
174 } => match key {
175 RegistryKey::FunctionName(name) => {
176 let function_name = FunctionName::Variant(name.to_string());
177 let cases = variant_type
178 .cases
179 .iter()
180 .map(|x| (x.name.clone(), x.typ.as_ref().map(InferredType::from)))
181 .collect::<Vec<_>>();
182
183 map.push((
184 function_name,
185 FunctionType {
186 parameter_types: parameter_types.iter().map(|x| x.into()).collect(),
187 return_type: Some(InferredType::variant(cases)),
188 },
189 ));
190 }
191 RegistryKey::FunctionNameWithInterface { .. } => {}
192 },
193
194 RegistryValue::Value(value) => match value {
195 AnalysedType::Enum(type_enum) => match key {
196 RegistryKey::FunctionName(name) => {
197 let function_name = FunctionName::Enum(name.to_string());
198
199 map.push((
200 function_name,
201 FunctionType {
202 parameter_types: vec![],
203 return_type: Some(InferredType::enum_(type_enum.cases.clone())),
204 },
205 ));
206 }
207 RegistryKey::FunctionNameWithInterface { .. } => {}
208 },
209 AnalysedType::Variant(variant_type) => match key {
210 RegistryKey::FunctionName(name) => {
211 let function_name = FunctionName::Variant(name.to_string());
212
213 let cases = variant_type
214 .cases
215 .iter()
216 .map(|x| (x.name.clone(), x.typ.as_ref().map(InferredType::from)))
217 .collect::<Vec<_>>();
218
219 map.push((
220 function_name,
221 FunctionType {
222 parameter_types: vec![],
223 return_type: Some(InferredType::variant(cases)),
224 },
225 ));
226 }
227 RegistryKey::FunctionNameWithInterface { .. } => {}
228 },
229
230 _ => {}
231 },
232 };
233 }
234
235 Ok(FunctionDictionary {
236 name_and_types: map,
237 })
238 }
239}
240
241fn resolve_function_name(
242 package_name: Option<PackageName>,
243 interface_name: Option<InterfaceName>,
244 function_name: &str,
245) -> Result<FunctionName, String> {
246 match get_resource_name(function_name) {
247 Some(resource_name) => Ok(FunctionName::ResourceConstructor(
248 FullyQualifiedResourceConstructor {
249 package_name,
250 interface_name,
251 resource_name,
252 },
253 )),
254 None => match get_resource_method_name(function_name) {
255 Ok(Some((constructor, method))) => {
256 Ok(FunctionName::ResourceMethod(FullyQualifiedResourceMethod {
257 package_name,
258 interface_name,
259 resource_name: constructor,
260 method_name: method,
261 static_function: false,
262 }))
263 }
264 Ok(None) => match get_resource_static_method_name(function_name) {
265 Ok(Some((constructor, method))) => {
266 Ok(FunctionName::ResourceMethod(FullyQualifiedResourceMethod {
267 package_name,
268 interface_name,
269 resource_name: constructor,
270 method_name: method,
271 static_function: true,
272 }))
273 }
274 Ok(None) => Ok(FunctionName::Function(FullyQualifiedFunctionName {
275 package_name,
276 interface_name,
277 function_name: function_name.to_string(),
278 })),
279
280 Err(e) => Err(format!("invalid resource static method call. {e}")),
281 },
282
283 Err(e) => Err(format!("invalid resource method call. {e}")),
284 },
285 }
286}
287
288fn get_resource_name(function_name: &str) -> Option<String> {
289 if function_name.trim().starts_with("[constructor]") {
290 Some(
291 function_name
292 .trim_start_matches("[constructor]")
293 .to_string(),
294 )
295 } else {
296 None
297 }
298}
299
300fn get_resource_static_method_name(
301 function_name: &str,
302) -> Result<Option<(String, String)>, String> {
303 if function_name.starts_with("[static]") {
304 let constructor_and_method = function_name.trim_start_matches("[static]").to_string();
305 let mut constructor_and_method = constructor_and_method.split('.');
306 let constructor = constructor_and_method.next();
307 let method = constructor_and_method.next();
308
309 match (constructor, method) {
310 (Some(constructor), Some(method)) => {
311 Ok(Some((constructor.to_string(), method.to_string())))
312 }
313 _ => Err(format!("Invalid resource method name: {function_name}")),
314 }
315 } else {
316 Ok(None)
317 }
318}
319
320fn get_resource_method_name(function_name: &str) -> Result<Option<(String, String)>, String> {
321 if function_name.starts_with("[method]") {
322 let constructor_and_method = function_name.trim_start_matches("[method]").to_string();
323 let mut constructor_and_method = constructor_and_method.split('.');
324 let constructor = constructor_and_method.next();
325 let method = constructor_and_method.next();
326
327 match (constructor, method) {
328 (Some(constructor), Some(method)) => {
329 Ok(Some((constructor.to_string(), method.to_string())))
330 }
331 _ => Err(format!("Invalid resource method name: {function_name}")),
332 }
333 } else if function_name.starts_with("[drop]") {
334 let constructor = function_name.trim_start_matches("[drop]").to_string();
335 Ok(Some((constructor, "drop".to_string())))
336 } else {
337 Ok(None)
338 }
339}
340
341#[derive(Debug, Hash, Clone, Eq, PartialEq, Ord, PartialOrd)]
342pub enum FunctionName {
343 Variant(String),
344 Enum(String),
345 Function(FullyQualifiedFunctionName),
346 ResourceConstructor(FullyQualifiedResourceConstructor),
347 ResourceMethod(FullyQualifiedResourceMethod),
348}
349
350impl Display for FunctionName {
351 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
352 write!(f, "{}", self.name())
353 }
354}
355
356impl FunctionName {
357 pub fn from_dynamic_parsed_function_name(
358 function_name: &DynamicParsedFunctionName,
359 ) -> FunctionName {
360 let site = &function_name.site;
361 let (package_name, interface_name) = match site {
362 ParsedFunctionSite::Global => (None, None),
363
364 ParsedFunctionSite::Interface { name } => (
365 None,
366 Some(InterfaceName {
367 name: name.clone(),
368 version: None,
369 }),
370 ),
371 ParsedFunctionSite::PackagedInterface {
372 namespace,
373 package,
374 interface,
375 version,
376 } => (
377 Some(PackageName {
378 namespace: namespace.clone(),
379 package_name: package.clone(),
380 version: None,
381 }),
382 Some(InterfaceName {
383 name: interface.clone(),
384 version: version.as_ref().map(|v| v.0.to_string()),
385 }),
386 ),
387 };
388
389 match &function_name.function {
390 DynamicParsedFunctionReference::Function { function } => {
391 FunctionName::Function(FullyQualifiedFunctionName {
392 package_name,
393 interface_name,
394 function_name: function.clone(),
395 })
396 }
397 DynamicParsedFunctionReference::RawResourceConstructor { resource } => {
398 FunctionName::ResourceConstructor(FullyQualifiedResourceConstructor {
399 package_name,
400 interface_name,
401 resource_name: resource.clone(),
402 })
403 }
404 DynamicParsedFunctionReference::RawResourceDrop { resource } => {
405 FunctionName::ResourceMethod(FullyQualifiedResourceMethod {
406 package_name,
407 interface_name,
408 resource_name: resource.clone(),
409 method_name: "drop".to_string(),
410 static_function: false,
411 })
412 }
413 DynamicParsedFunctionReference::RawResourceMethod { resource, method } => {
414 FunctionName::ResourceMethod(FullyQualifiedResourceMethod {
415 package_name,
416 interface_name,
417 resource_name: resource.clone(),
418 method_name: method.clone(),
419 static_function: false,
420 })
421 }
422 DynamicParsedFunctionReference::RawResourceStaticMethod { resource, method } => {
423 FunctionName::ResourceMethod(FullyQualifiedResourceMethod {
424 package_name,
425 interface_name,
426 resource_name: resource.clone(),
427 method_name: method.clone(),
428 static_function: true,
429 })
430 }
431 }
432 }
433
434 pub fn from_call_type(call_type: &CallType) -> Option<FunctionName> {
435 match call_type {
436 CallType::VariantConstructor(variant_name) => {
437 Some(FunctionName::Variant(variant_name.clone()))
438 }
439 CallType::EnumConstructor(enum_name) => Some(FunctionName::Enum(enum_name.clone())),
440 CallType::Function { function_name, .. } => {
441 Some(Self::from_dynamic_parsed_function_name(function_name))
442 }
443 CallType::InstanceCreation(_) => None,
444 }
445 }
446
447 pub fn interface_name(&self) -> Option<InterfaceName> {
448 match self {
449 FunctionName::Function(fqfn) => fqfn.interface_name.clone(),
450 FunctionName::ResourceConstructor(fqfn) => fqfn.interface_name.clone(),
451 FunctionName::ResourceMethod(resource_method) => resource_method.interface_name.clone(),
452 FunctionName::Variant(_) => None,
453 FunctionName::Enum(_) => None,
454 }
455 }
456
457 pub fn package_name(&self) -> Option<PackageName> {
458 match self {
459 FunctionName::Function(fqfn) => fqfn.package_name.clone(),
460 FunctionName::ResourceConstructor(fqfn) => fqfn.package_name.clone(),
461 FunctionName::ResourceMethod(fqfn) => fqfn.package_name.clone(),
462 FunctionName::Variant(_) => None,
463 FunctionName::Enum(_) => None,
464 }
465 }
466
467 pub fn name(&self) -> String {
468 match self {
469 FunctionName::Function(fqfn) => fqfn.function_name.to_string(),
470 FunctionName::ResourceConstructor(fqfn) => fqfn.resource_name.to_string(),
471 FunctionName::ResourceMethod(fqfn) => fqfn.method_name.to_string(),
472 FunctionName::Variant(name) => name.clone(),
473 FunctionName::Enum(name) => name.clone(),
474 }
475 }
476}
477
478#[derive(Debug, Hash, Clone, Eq, PartialEq, Ord, PartialOrd)]
479pub struct FullyQualifiedResourceConstructor {
480 pub package_name: Option<PackageName>,
481 pub interface_name: Option<InterfaceName>,
482 pub resource_name: String,
483}
484
485impl FullyQualifiedResourceConstructor {
486 pub fn parsed_function_site(&self) -> ParsedFunctionSite {
487 if let Some(package_name) = &self.package_name {
488 let interface_name = self.interface_name.clone().unwrap();
489
490 ParsedFunctionSite::PackagedInterface {
491 namespace: package_name.namespace.clone(),
492 package: package_name.package_name.clone(),
493 interface: self
494 .interface_name
495 .as_ref()
496 .map_or_else(|| "".to_string(), |i| i.name.clone()),
497 version: interface_name
498 .version
499 .map(|x| SemVer(semver::Version::parse(&x).unwrap())),
500 }
501 } else if let Some(interface_name) = &self.interface_name {
502 ParsedFunctionSite::Interface {
503 name: interface_name.name.clone(),
504 }
505 } else {
506 ParsedFunctionSite::Global
507 }
508 }
509}
510
511#[derive(Debug, Hash, Clone, Eq, PartialEq, Ord, PartialOrd)]
512pub struct FullyQualifiedFunctionName {
513 pub package_name: Option<PackageName>,
514 pub interface_name: Option<InterfaceName>,
515 pub function_name: String,
516}
517
518#[derive(Debug, Hash, Clone, Eq, PartialEq, Ord, PartialOrd)]
519pub struct FullyQualifiedResourceMethod {
520 pub package_name: Option<PackageName>,
521 pub interface_name: Option<InterfaceName>,
522 pub resource_name: String,
523 pub method_name: String,
524 pub static_function: bool,
525}
526
527impl FullyQualifiedResourceMethod {
528 pub fn get_constructor(&self) -> FullyQualifiedResourceConstructor {
529 FullyQualifiedResourceConstructor {
530 package_name: self.package_name.clone(),
531 interface_name: self.interface_name.clone(),
532 resource_name: self.resource_name.clone(),
533 }
534 }
535
536 pub fn dynamic_parsed_function_name(&self) -> Result<DynamicParsedFunctionName, String> {
539 let mut dynamic_parsed_str = String::new();
540
541 if let Some(package) = &self.package_name {
543 dynamic_parsed_str.push_str(&package.to_string());
544 dynamic_parsed_str.push('/');
545 }
546
547 if let Some(interface) = &self.interface_name {
548 dynamic_parsed_str.push_str(&interface.to_string());
549 dynamic_parsed_str.push('.');
550 }
551
552 dynamic_parsed_str.push('{');
553 if self.static_function {
554 dynamic_parsed_str.push_str("[static]");
555 } else {
556 dynamic_parsed_str.push_str("[method]");
557 }
558
559 dynamic_parsed_str.push_str(&self.resource_name);
560 dynamic_parsed_str.push('.');
561 dynamic_parsed_str.push_str(&self.method_name);
562 dynamic_parsed_str.push('}');
563
564 DynamicParsedFunctionName::parse(dynamic_parsed_str)
565 }
566
567 pub fn method_name(&self) -> &String {
568 &self.method_name
569 }
570}
571
572impl Display for FullyQualifiedFunctionName {
573 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
574 if let Some(package_name) = &self.package_name {
575 write!(f, "{package_name}")?
576 }
577
578 if let Some(interface_name) = &self.interface_name {
579 write!(f, "/{interface_name}.")?;
580 write!(f, "{{{}}}", self.function_name)
581 } else {
582 write!(f, "{}", self.function_name)
583 }
584 }
585}
586
587#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
588pub struct FunctionType {
589 pub parameter_types: Vec<InferredType>,
590 pub return_type: Option<InferredType>,
591}
592
593impl FunctionType {
594 pub fn as_type_variant(&self) -> Option<TypeVariant> {
595 let analysed_type = AnalysedType::try_from(&self.return_type.clone()?).ok()?;
596
597 match analysed_type {
598 AnalysedType::Variant(type_variant) => Some(type_variant),
599 _ => None,
600 }
601 }
602
603 pub fn as_type_enum(&self) -> Option<TypeEnum> {
604 let analysed_type = AnalysedType::try_from(&self.return_type.clone()?).ok()?;
605 match analysed_type {
606 AnalysedType::Enum(type_enum) => Some(type_enum),
607 _ => None,
608 }
609 }
610
611 pub fn parameter_types(&self) -> Vec<AnalysedType> {
612 self.parameter_types
613 .iter()
614 .map(|x| AnalysedType::try_from(x).unwrap())
615 .collect()
616 }
617
618 pub fn return_type(&self) -> Option<AnalysedType> {
619 self.return_type
620 .clone()
621 .map(|x| AnalysedType::try_from(&x).unwrap())
622 }
623}
624
625#[cfg(feature = "protobuf")]
626mod protobuf {
627 use crate::FunctionName;
628
629 impl TryFrom<golem_api_grpc::proto::golem::rib::function_name_type::FunctionName> for FunctionName {
630 type Error = String;
631
632 fn try_from(
633 value: golem_api_grpc::proto::golem::rib::function_name_type::FunctionName,
634 ) -> Result<Self, Self::Error> {
635 match value {
636 golem_api_grpc::proto::golem::rib::function_name_type::FunctionName::VariantName(name) => {
637 Ok(FunctionName::Variant(name))
638 }
639 golem_api_grpc::proto::golem::rib::function_name_type::FunctionName::EnumName(name) => {
640 Ok(FunctionName::Enum(name))
641 }
642 golem_api_grpc::proto::golem::rib::function_name_type::FunctionName::Function(fqfn) => {
643 Ok(FunctionName::Function(fqfn.try_into()?))
644 }
645 golem_api_grpc::proto::golem::rib::function_name_type::FunctionName::ResourceConstructor(fqrc) => {
646 Ok(FunctionName::ResourceConstructor(fqrc.try_into()?))
647 }
648 golem_api_grpc::proto::golem::rib::function_name_type::FunctionName::ResourceMethod(fqrm) => {
649 Ok(FunctionName::ResourceMethod(fqrm.try_into()?))
650 }
651 }
652 }
653 }
654
655 impl From<FunctionName> for golem_api_grpc::proto::golem::rib::function_name_type::FunctionName {
656 fn from(value: FunctionName) -> Self {
657 match value {
658 FunctionName::Variant(name) => {
659 golem_api_grpc::proto::golem::rib::function_name_type::FunctionName::VariantName(name)
660 }
661 FunctionName::Enum(name) => {
662 golem_api_grpc::proto::golem::rib::function_name_type::FunctionName::EnumName(name)
663 }
664 FunctionName::Function(fqfn) => {
665 golem_api_grpc::proto::golem::rib::function_name_type::FunctionName::Function(fqfn.into())
666 }
667 FunctionName::ResourceConstructor(fqrc) => {
668 golem_api_grpc::proto::golem::rib::function_name_type::FunctionName::ResourceConstructor(fqrc.into())
669 }
670 FunctionName::ResourceMethod(fqrm) => {
671 golem_api_grpc::proto::golem::rib::function_name_type::FunctionName::ResourceMethod(fqrm.into())
672 }
673 }
674 }
675 }
676}