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