1use crate::Expr;
16use bincode::{BorrowDecode, Decode, Encode};
17use combine::stream::position::Stream;
18use combine::{eof, EasyParser, Parser};
19use golem_wasm_rpc::{parse_value_and_type, ValueAndType};
20use semver::{BuildMetadata, Prerelease};
21use serde::{Deserialize, Serialize};
22use std::borrow::Cow;
23use std::fmt::Display;
24
25#[derive(PartialEq, Hash, Eq, Clone, Ord, PartialOrd)]
26pub struct SemVer(pub semver::Version);
27
28impl SemVer {
29 pub fn parse(version: &str) -> Result<Self, String> {
30 semver::Version::parse(version)
31 .map(SemVer)
32 .map_err(|e| format!("Invalid semver string: {e}"))
33 }
34}
35
36impl std::fmt::Debug for SemVer {
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38 write!(f, "{}", self.0)
39 }
40}
41
42impl Encode for SemVer {
43 fn encode<E: bincode::enc::Encoder>(
44 &self,
45 encoder: &mut E,
46 ) -> Result<(), bincode::error::EncodeError> {
47 self.0.major.encode(encoder)?;
48 self.0.minor.encode(encoder)?;
49 self.0.patch.encode(encoder)?;
50 self.0.pre.as_str().encode(encoder)?;
51 self.0.build.as_str().encode(encoder)?;
52 Ok(())
53 }
54}
55
56impl<Context> Decode<Context> for SemVer {
57 fn decode<D: bincode::de::Decoder<Context = Context>>(
58 decoder: &mut D,
59 ) -> Result<Self, bincode::error::DecodeError> {
60 let major = u64::decode(decoder)?;
61 let minor = u64::decode(decoder)?;
62 let patch = u64::decode(decoder)?;
63 let pre_str = String::decode(decoder)?;
64 let build_str = String::decode(decoder)?;
65 let pre = Prerelease::new(&pre_str)
66 .map_err(|_| bincode::error::DecodeError::OtherString("Invalid prerelease".into()))?;
67 let build = BuildMetadata::new(&build_str).map_err(|_| {
68 bincode::error::DecodeError::OtherString("Invalid build metadata".into())
69 })?;
70
71 Ok(SemVer(semver::Version {
72 major,
73 minor,
74 patch,
75 pre,
76 build,
77 }))
78 }
79}
80
81impl<'de, Context> BorrowDecode<'de, Context> for SemVer {
82 fn borrow_decode<D: bincode::de::BorrowDecoder<'de, Context = Context>>(
83 decoder: &mut D,
84 ) -> Result<Self, bincode::error::DecodeError> {
85 let major = u64::borrow_decode(decoder)?;
86 let minor = u64::borrow_decode(decoder)?;
87 let patch = u64::borrow_decode(decoder)?;
88 let pre_str = <Cow<'de, str> as BorrowDecode<Context>>::borrow_decode(decoder)?;
89 let build_str = <Cow<'de, str> as BorrowDecode<Context>>::borrow_decode(decoder)?;
90 let pre = Prerelease::new(&pre_str)
91 .map_err(|_| bincode::error::DecodeError::OtherString("Invalid prerelease".into()))?;
92 let build = BuildMetadata::new(&build_str).map_err(|_| {
93 bincode::error::DecodeError::OtherString("Invalid build metadata".into())
94 })?;
95 Ok(SemVer(semver::Version {
96 major,
97 minor,
98 patch,
99 pre,
100 build,
101 }))
102 }
103}
104
105#[derive(Debug, Hash, PartialEq, Eq, Clone, Encode, Decode, Ord, PartialOrd)]
106pub enum ParsedFunctionSite {
107 Global,
108 Interface {
109 name: String,
110 },
111 PackagedInterface {
112 namespace: String,
113 package: String,
114 interface: String,
115 version: Option<SemVer>,
116 },
117}
118
119impl ParsedFunctionSite {
120 pub fn parse(name: impl AsRef<str>) -> Result<Self, String> {
121 ParsedFunctionName::parse(format!("{}.{{x}}", name.as_ref()))
122 .map(|ParsedFunctionName { site, .. }| site)
123 }
124
125 pub fn interface_name(&self) -> Option<String> {
126 match self {
127 Self::Global => None,
128 Self::Interface { name } => Some(name.clone()),
129 Self::PackagedInterface {
130 namespace,
131 package,
132 interface,
133 version: None,
134 } => Some(format!("{namespace}:{package}/{interface}")),
135 Self::PackagedInterface {
136 namespace,
137 package,
138 interface,
139 version: Some(version),
140 } => Some(format!("{namespace}:{package}/{interface}@{}", version.0)),
141 }
142 }
143
144 pub fn unversioned(&self) -> ParsedFunctionSite {
145 match self {
146 ParsedFunctionSite::Global => ParsedFunctionSite::Global,
147 ParsedFunctionSite::Interface { name } => {
148 ParsedFunctionSite::Interface { name: name.clone() }
149 }
150 ParsedFunctionSite::PackagedInterface {
151 namespace,
152 package,
153 interface,
154 version: _,
155 } => ParsedFunctionSite::PackagedInterface {
156 namespace: namespace.clone(),
157 package: package.clone(),
158 interface: interface.clone(),
159 version: None,
160 },
161 }
162 }
163}
164
165#[derive(Debug, Hash, PartialEq, Eq, Clone, Ord, PartialOrd)]
166pub enum DynamicParsedFunctionReference {
167 Function {
168 function: String,
169 },
170 RawResourceConstructor {
171 resource: String,
172 },
173 RawResourceDrop {
174 resource: String,
175 },
176 RawResourceMethod {
177 resource: String,
178 method: String,
179 },
180 RawResourceStaticMethod {
181 resource: String,
182 method: String,
183 },
184 IndexedResourceConstructor {
185 resource: String,
186 resource_params: Vec<Expr>,
187 },
188 IndexedResourceMethod {
189 resource: String,
190 resource_params: Vec<Expr>,
191 method: String,
192 },
193 IndexedResourceStaticMethod {
194 resource: String,
195 resource_params: Vec<Expr>,
196 method: String,
197 },
198 IndexedResourceDrop {
199 resource: String,
200 resource_params: Vec<Expr>,
201 },
202}
203
204impl DynamicParsedFunctionReference {
205 pub fn name_pretty(&self) -> String {
206 match self {
207 DynamicParsedFunctionReference::Function { function, .. } => function.clone(),
208 DynamicParsedFunctionReference::RawResourceConstructor { resource, .. } => {
209 resource.to_string()
210 }
211 DynamicParsedFunctionReference::RawResourceDrop { .. } => "drop".to_string(),
212 DynamicParsedFunctionReference::RawResourceMethod { method, .. } => method.to_string(),
213 DynamicParsedFunctionReference::RawResourceStaticMethod { method, .. } => {
214 method.to_string()
215 }
216 DynamicParsedFunctionReference::IndexedResourceConstructor {
217 resource,
218 resource_params,
219 } => format!(
220 "{}({})",
221 resource,
222 resource_params
223 .iter()
224 .map(|x| x.to_string())
225 .collect::<Vec<_>>()
226 .join(", ")
227 ),
228 DynamicParsedFunctionReference::IndexedResourceMethod { method, .. } => {
229 method.to_string()
230 }
231 DynamicParsedFunctionReference::IndexedResourceStaticMethod { method, .. } => {
232 method.to_string()
233 }
234 DynamicParsedFunctionReference::IndexedResourceDrop { .. } => "drop".to_string(),
235 }
236 }
237
238 fn to_static(&self) -> ParsedFunctionReference {
239 match self {
240 Self::Function { function } => ParsedFunctionReference::Function {
241 function: function.clone(),
242 },
243 Self::RawResourceConstructor { resource } => {
244 ParsedFunctionReference::RawResourceConstructor {
245 resource: resource.clone(),
246 }
247 }
248 Self::RawResourceDrop { resource } => ParsedFunctionReference::RawResourceDrop {
249 resource: resource.clone(),
250 },
251 Self::RawResourceMethod { resource, method } => {
252 ParsedFunctionReference::RawResourceMethod {
253 resource: resource.clone(),
254 method: method.clone(),
255 }
256 }
257 Self::RawResourceStaticMethod { resource, method } => {
258 ParsedFunctionReference::RawResourceStaticMethod {
259 resource: resource.clone(),
260 method: method.clone(),
261 }
262 }
263 Self::IndexedResourceConstructor {
264 resource,
265 resource_params,
266 } => ParsedFunctionReference::IndexedResourceConstructor {
267 resource: resource.clone(),
268 resource_params: resource_params
269 .iter()
270 .map(|expr| expr.to_string())
271 .collect(),
272 },
273 Self::IndexedResourceMethod {
274 resource,
275 resource_params,
276 method,
277 } => ParsedFunctionReference::IndexedResourceMethod {
278 resource: resource.clone(),
279 resource_params: resource_params
280 .iter()
281 .map(|expr| expr.to_string())
282 .collect(),
283 method: method.clone(),
284 },
285 Self::IndexedResourceStaticMethod {
286 resource,
287 resource_params,
288 method,
289 } => ParsedFunctionReference::IndexedResourceStaticMethod {
290 resource: resource.clone(),
291 resource_params: resource_params
292 .iter()
293 .map(|expr| expr.to_string())
294 .collect(),
295 method: method.clone(),
296 },
297 Self::IndexedResourceDrop {
298 resource,
299 resource_params,
300 } => ParsedFunctionReference::IndexedResourceDrop {
301 resource: resource.clone(),
302 resource_params: resource_params
303 .iter()
304 .map(|expr| expr.to_string())
305 .collect(),
306 },
307 }
308 }
309
310 pub fn raw_resource_params_mut(&mut self) -> Option<&mut [Expr]> {
311 match self {
312 Self::IndexedResourceConstructor {
313 resource_params, ..
314 }
315 | Self::IndexedResourceMethod {
316 resource_params, ..
317 }
318 | Self::IndexedResourceStaticMethod {
319 resource_params, ..
320 }
321 | Self::IndexedResourceDrop {
322 resource_params, ..
323 } => Some(resource_params.as_mut_slice()),
324 _ => None,
325 }
326 }
327
328 pub fn raw_resource_params(&self) -> Option<&Vec<Expr>> {
329 match self {
330 Self::IndexedResourceConstructor {
331 resource_params, ..
332 }
333 | Self::IndexedResourceMethod {
334 resource_params, ..
335 }
336 | Self::IndexedResourceStaticMethod {
337 resource_params, ..
338 }
339 | Self::IndexedResourceDrop {
340 resource_params, ..
341 } => Some(resource_params),
342 _ => None,
343 }
344 }
345}
346
347#[derive(Debug, PartialEq, Eq, Clone, Hash, Encode, Decode)]
348pub enum ParsedFunctionReference {
349 Function {
350 function: String,
351 },
352 RawResourceConstructor {
353 resource: String,
354 },
355 RawResourceDrop {
356 resource: String,
357 },
358 RawResourceMethod {
359 resource: String,
360 method: String,
361 },
362 RawResourceStaticMethod {
363 resource: String,
364 method: String,
365 },
366 IndexedResourceConstructor {
367 resource: String,
368 resource_params: Vec<String>,
369 },
370 IndexedResourceMethod {
371 resource: String,
372 resource_params: Vec<String>,
373 method: String,
374 },
375 IndexedResourceStaticMethod {
376 resource: String,
377 resource_params: Vec<String>,
378 method: String,
379 },
380 IndexedResourceDrop {
381 resource: String,
382 resource_params: Vec<String>,
383 },
384}
385
386impl Display for ParsedFunctionReference {
387 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
388 let function_name = match self {
389 Self::Function { function } => function.clone(),
390 Self::RawResourceConstructor { resource } => format!("{resource}.new"),
391 Self::IndexedResourceConstructor {
392 resource,
393 resource_params,
394 } => {
395 format!("{}({}).new", resource, resource_params.join(", "))
396 }
397 Self::RawResourceMethod { resource, method } => format!("{resource}.{method}"),
398 Self::RawResourceStaticMethod { resource, method } => {
399 format!("[static]{resource}.{method}")
400 }
401 Self::RawResourceDrop { resource } => format!("{resource}.drop"),
402 Self::IndexedResourceDrop {
403 resource,
404 resource_params,
405 } => {
406 format!("{}({}).drop", resource, resource_params.join(", "))
407 }
408 Self::IndexedResourceMethod {
409 resource,
410 resource_params,
411 method,
412 } => {
413 format!("{}({}).{}", resource, resource_params.join(", "), method)
414 }
415 Self::IndexedResourceStaticMethod {
416 resource,
417 resource_params,
418 method,
419 } => {
420 format!(
421 "[static]{}({}).{}",
422 resource,
423 resource_params.join(", "),
424 method
425 )
426 }
427 };
428
429 write!(f, "{function_name}")
430 }
431}
432
433impl ParsedFunctionReference {
434 pub fn function_name(&self) -> String {
435 match self {
436 Self::Function { function, .. } => function.clone(),
437 Self::RawResourceConstructor { resource, .. } => format!("[constructor]{resource}"),
438 Self::RawResourceDrop { resource, .. } => format!("[drop]{resource}"),
439 Self::RawResourceMethod {
440 resource, method, ..
441 } => format!("[method]{resource}.{method}"),
442 Self::RawResourceStaticMethod {
443 resource, method, ..
444 } => format!("[static]{resource}.{method}"),
445 Self::IndexedResourceConstructor { resource, .. } => {
446 format!("[constructor]{resource}")
447 }
448 Self::IndexedResourceMethod {
449 resource, method, ..
450 } => {
451 format!("[method]{resource}.{method}")
452 }
453 Self::IndexedResourceStaticMethod {
454 resource, method, ..
455 } => {
456 format!("[static]{resource}.{method}")
457 }
458 Self::IndexedResourceDrop { resource, .. } => {
459 format!("[drop]{resource}")
460 }
461 }
462 }
463
464 pub fn resource_method_name(&self) -> Option<String> {
465 match self {
466 Self::IndexedResourceStaticMethod { method, .. }
467 | Self::RawResourceMethod { method, .. }
468 | Self::RawResourceStaticMethod { method, .. }
469 | Self::IndexedResourceMethod { method, .. } => Some(method.clone()),
470 _ => None,
471 }
472 }
473
474 pub fn method_as_static(&self) -> Option<ParsedFunctionReference> {
475 match self {
476 Self::RawResourceMethod { resource, method } => Some(Self::RawResourceStaticMethod {
477 resource: resource.clone(),
478 method: method.clone(),
479 }),
480 Self::IndexedResourceMethod {
481 resource,
482 resource_params,
483 method,
484 } => Some(Self::IndexedResourceStaticMethod {
485 resource: resource.clone(),
486 resource_params: resource_params.clone(),
487 method: method.clone(),
488 }),
489 _ => None,
490 }
491 }
492
493 pub fn is_indexed_resource(&self) -> bool {
494 matches!(
495 self,
496 Self::IndexedResourceConstructor { .. }
497 | Self::IndexedResourceMethod { .. }
498 | Self::IndexedResourceStaticMethod { .. }
499 | Self::IndexedResourceDrop { .. }
500 )
501 }
502
503 pub fn raw_resource_params(&self) -> Option<&Vec<String>> {
504 match self {
505 Self::IndexedResourceConstructor {
506 resource_params, ..
507 }
508 | Self::IndexedResourceMethod {
509 resource_params, ..
510 }
511 | Self::IndexedResourceStaticMethod {
512 resource_params, ..
513 }
514 | Self::IndexedResourceDrop {
515 resource_params, ..
516 } => Some(resource_params),
517 _ => None,
518 }
519 }
520
521 pub fn resource_name(&self) -> Option<&String> {
522 match self {
523 Self::RawResourceConstructor { resource }
524 | Self::RawResourceDrop { resource }
525 | Self::RawResourceMethod { resource, .. }
526 | Self::RawResourceStaticMethod { resource, .. }
527 | Self::IndexedResourceConstructor { resource, .. }
528 | Self::IndexedResourceMethod { resource, .. }
529 | Self::IndexedResourceStaticMethod { resource, .. }
530 | Self::IndexedResourceDrop { resource, .. } => Some(resource),
531 _ => None,
532 }
533 }
534
535 pub fn resource_params(
536 &self,
537 types: &[golem_wasm_ast::analysis::AnalysedType],
538 ) -> Result<Option<Vec<ValueAndType>>, String> {
539 if let Some(raw_params) = self.raw_resource_params() {
540 if raw_params.len() != types.len() {
541 Err(format!(
542 "Resource params count mismatch: expected {}, got {}",
543 types.len(),
544 raw_params.len()
545 ))
546 } else {
547 let mut result = Vec::new();
548 for (raw_param, param_type) in raw_params.iter().zip(types.iter()) {
549 let value_and_type: ValueAndType = parse_value_and_type(param_type, raw_param)?;
550 result.push(value_and_type);
551 }
552 Ok(Some(result))
553 }
554 } else {
555 Ok(None)
556 }
557 }
558}
559
560#[derive(Debug, Hash, PartialEq, Eq, Clone, Ord, PartialOrd)]
569pub struct DynamicParsedFunctionName {
570 pub site: ParsedFunctionSite,
571 pub function: DynamicParsedFunctionReference,
572}
573
574impl DynamicParsedFunctionName {
575 pub fn parse(name: impl AsRef<str>) -> Result<Self, String> {
576 let name = name.as_ref();
577
578 let mut parser = crate::parser::call::function_name();
579
580 let result = parser.easy_parse(Stream::new(name));
581
582 match result {
583 Ok((parsed, _)) => Ok(parsed),
584 Err(error) => {
585 let error_message = error.map_position(|p| p.to_string()).to_string();
586 Err(error_message)
587 }
588 }
589 }
590
591 pub fn function_name_with_prefix_identifiers(&self) -> String {
592 self.to_parsed_function_name().function.function_name()
593 }
594
595 pub fn resource_name_simplified(&self) -> Option<String> {
598 self.to_parsed_function_name()
599 .function
600 .resource_name()
601 .cloned()
602 }
603
604 pub fn resource_method_name_simplified(&self) -> Option<String> {
606 self.to_parsed_function_name()
607 .function
608 .resource_method_name()
609 }
610
611 pub fn raw_resource_params_mut(&mut self) -> Option<&mut [Expr]> {
612 self.function.raw_resource_params_mut()
613 }
614
615 pub fn to_parsed_function_name(&self) -> ParsedFunctionName {
617 ParsedFunctionName {
618 site: self.site.clone(),
619 function: self.function.to_static(),
620 }
621 }
622}
623
624impl Display for DynamicParsedFunctionName {
625 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
626 let function_name = self.to_parsed_function_name().to_string();
627 write!(f, "{function_name}")
628 }
629}
630
631#[derive(Debug, PartialEq, Eq, Clone, Hash, Encode, Decode)]
632pub struct ParsedFunctionName {
633 pub site: ParsedFunctionSite,
634 pub function: ParsedFunctionReference,
635}
636
637impl Serialize for ParsedFunctionName {
638 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
639 let function_name = self.to_string();
640 serializer.serialize_str(&function_name)
641 }
642}
643
644impl<'de> Deserialize<'de> for ParsedFunctionName {
645 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
646 where
647 D: serde::Deserializer<'de>,
648 {
649 let function_name = String::deserialize(deserializer)?;
650 ParsedFunctionName::parse(function_name).map_err(serde::de::Error::custom)
651 }
652}
653
654impl Display for ParsedFunctionName {
655 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
656 let function_name = self
657 .site
658 .interface_name()
659 .map_or(self.function.function_name(), |interface| {
660 format!("{}.{{{}}}", interface, self.function)
661 });
662 write!(f, "{function_name}")
663 }
664}
665
666impl ParsedFunctionName {
667 pub fn new(site: ParsedFunctionSite, function: ParsedFunctionReference) -> Self {
668 Self { site, function }
669 }
670
671 pub fn global(name: String) -> Self {
672 Self {
673 site: ParsedFunctionSite::Global,
674 function: ParsedFunctionReference::Function { function: name },
675 }
676 }
677
678 pub fn on_interface(interface: String, function: String) -> Self {
679 Self {
680 site: ParsedFunctionSite::Interface { name: interface },
681 function: ParsedFunctionReference::Function { function },
682 }
683 }
684
685 pub fn parse(name: impl AsRef<str>) -> Result<Self, String> {
686 let name = name.as_ref();
687
688 let mut parser = crate::parser::call::function_name().skip(eof());
689
690 let result = parser.easy_parse(Stream::new(name));
691
692 match result {
693 Ok((parsed, _)) => Ok(parsed.to_parsed_function_name()),
694 Err(error) => {
695 let error_message = error.map_position(|p| p.to_string()).to_string();
696 Err(error_message)
697 }
698 }
699 }
700
701 pub fn site(&self) -> &ParsedFunctionSite {
702 &self.site
703 }
704
705 pub fn function(&self) -> &ParsedFunctionReference {
706 &self.function
707 }
708
709 pub fn method_as_static(&self) -> Option<Self> {
710 self.function.method_as_static().map(|function| Self {
711 site: self.site.clone(),
712 function,
713 })
714 }
715
716 pub fn is_constructor(&self) -> Option<&str> {
717 match &self.function {
718 ParsedFunctionReference::RawResourceConstructor { resource, .. }
719 | ParsedFunctionReference::IndexedResourceConstructor { resource, .. } => {
720 Some(resource)
721 }
722 _ => None,
723 }
724 }
725
726 pub fn is_method(&self) -> Option<&str> {
727 match &self.function {
728 ParsedFunctionReference::RawResourceMethod { resource, .. }
729 | ParsedFunctionReference::IndexedResourceMethod { resource, .. }
730 | ParsedFunctionReference::RawResourceStaticMethod { resource, .. }
731 | ParsedFunctionReference::IndexedResourceStaticMethod { resource, .. } => {
732 Some(resource)
733 }
734 _ => None,
735 }
736 }
737
738 pub fn is_static_method(&self) -> Option<&str> {
739 match &self.function {
740 ParsedFunctionReference::RawResourceStaticMethod { resource, .. }
741 | ParsedFunctionReference::IndexedResourceStaticMethod { resource, .. } => {
742 Some(resource)
743 }
744 _ => None,
745 }
746 }
747
748 pub fn with_site(&self, site: ParsedFunctionSite) -> Self {
749 Self {
750 site,
751 function: self.function.clone(),
752 }
753 }
754}
755
756#[cfg(feature = "protobuf")]
757mod protobuf {
758 use crate::{
759 DynamicParsedFunctionName, DynamicParsedFunctionReference, Expr, ParsedFunctionName,
760 ParsedFunctionReference, ParsedFunctionSite, SemVer,
761 };
762 use golem_api_grpc::proto::golem::rib::dynamic_parsed_function_reference::FunctionReference as ProtoDynamicFunctionReference;
763 use semver::{BuildMetadata, Prerelease};
764
765 impl TryFrom<golem_api_grpc::proto::golem::rib::SemVersion> for SemVer {
766 type Error = String;
767
768 fn try_from(
769 value: golem_api_grpc::proto::golem::rib::SemVersion,
770 ) -> Result<Self, Self::Error> {
771 Ok(SemVer(semver::Version {
772 major: value.major,
773 minor: value.minor,
774 patch: value.patch,
775 pre: Prerelease::new(&value.pre).map_err(|_| "Invalid prerelease".to_string())?,
776 build: BuildMetadata::new(&value.build)
777 .map_err(|_| "Invalid build metadata".to_string())?,
778 }))
779 }
780 }
781
782 impl From<SemVer> for golem_api_grpc::proto::golem::rib::SemVersion {
783 fn from(value: SemVer) -> Self {
784 golem_api_grpc::proto::golem::rib::SemVersion {
785 major: value.0.major,
786 minor: value.0.minor,
787 patch: value.0.patch,
788 pre: value.0.pre.to_string(),
789 build: value.0.build.to_string(),
790 }
791 }
792 }
793
794 impl TryFrom<golem_api_grpc::proto::golem::rib::ParsedFunctionSite> for ParsedFunctionSite {
795 type Error = String;
796
797 fn try_from(
798 value: golem_api_grpc::proto::golem::rib::ParsedFunctionSite,
799 ) -> Result<Self, Self::Error> {
800 let site = value.site.ok_or("Missing site".to_string())?;
801 match site {
802 golem_api_grpc::proto::golem::rib::parsed_function_site::Site::Global(_) => {
803 Ok(Self::Global)
804 }
805 golem_api_grpc::proto::golem::rib::parsed_function_site::Site::Interface(
806 golem_api_grpc::proto::golem::rib::InterfaceFunctionSite { name },
807 ) => Ok(Self::Interface { name }),
808 golem_api_grpc::proto::golem::rib::parsed_function_site::Site::PackageInterface(
809 golem_api_grpc::proto::golem::rib::PackageInterfaceFunctionSite {
810 namespace,
811 package,
812 interface,
813 version,
814 },
815 ) => {
816 let version = match version {
817 Some(version) => Some(version.try_into()?),
818 None => None,
819 };
820
821 Ok(Self::PackagedInterface {
822 namespace,
823 package,
824 interface,
825 version,
826 })
827 }
828 }
829 }
830 }
831
832 impl From<ParsedFunctionSite> for golem_api_grpc::proto::golem::rib::ParsedFunctionSite {
833 fn from(value: ParsedFunctionSite) -> Self {
834 let site = match value {
835 ParsedFunctionSite::Global => {
836 golem_api_grpc::proto::golem::rib::parsed_function_site::Site::Global(
837 golem_api_grpc::proto::golem::rib::GlobalFunctionSite {},
838 )
839 }
840 ParsedFunctionSite::Interface { name } => {
841 golem_api_grpc::proto::golem::rib::parsed_function_site::Site::Interface(
842 golem_api_grpc::proto::golem::rib::InterfaceFunctionSite { name },
843 )
844 }
845 ParsedFunctionSite::PackagedInterface {
846 namespace,
847 package,
848 interface,
849 version,
850 } => {
851 golem_api_grpc::proto::golem::rib::parsed_function_site::Site::PackageInterface(
852 golem_api_grpc::proto::golem::rib::PackageInterfaceFunctionSite {
853 namespace,
854 package,
855 interface,
856 version: version.map(|v| v.into()),
857 },
858 )
859 }
860 };
861 golem_api_grpc::proto::golem::rib::ParsedFunctionSite { site: Some(site) }
862 }
863 }
864
865 impl From<DynamicParsedFunctionReference>
866 for golem_api_grpc::proto::golem::rib::DynamicParsedFunctionReference
867 {
868 fn from(value: DynamicParsedFunctionReference) -> Self {
869 let function = match value {
870 DynamicParsedFunctionReference::Function { function } => ProtoDynamicFunctionReference::Function(
871 golem_api_grpc::proto::golem::rib::FunctionFunctionReference { function },
872 ),
873 DynamicParsedFunctionReference::RawResourceConstructor { resource } => ProtoDynamicFunctionReference::RawResourceConstructor(
874 golem_api_grpc::proto::golem::rib::RawResourceConstructorFunctionReference { resource },
875 ),
876 DynamicParsedFunctionReference::RawResourceMethod { resource, method } => ProtoDynamicFunctionReference::RawResourceMethod(
877 golem_api_grpc::proto::golem::rib::RawResourceMethodFunctionReference { resource, method },
878 ),
879 DynamicParsedFunctionReference::RawResourceStaticMethod { resource, method } => ProtoDynamicFunctionReference::RawResourceStaticMethod(
880 golem_api_grpc::proto::golem::rib::RawResourceStaticMethodFunctionReference { resource, method },
881 ),
882 DynamicParsedFunctionReference::RawResourceDrop { resource } => ProtoDynamicFunctionReference::RawResourceDrop(
883 golem_api_grpc::proto::golem::rib::RawResourceDropFunctionReference { resource },
884 ),
885 DynamicParsedFunctionReference::IndexedResourceConstructor { resource, resource_params } => ProtoDynamicFunctionReference::IndexedResourceConstructor(
886 golem_api_grpc::proto::golem::rib::DynamicIndexedResourceConstructorFunctionReference {
887 resource,
888 resource_params: resource_params.into_iter().map(|x| x.into()).collect(),
889 },
890 ),
891 DynamicParsedFunctionReference::IndexedResourceMethod { resource, resource_params, method } => ProtoDynamicFunctionReference::IndexedResourceMethod(
892 golem_api_grpc::proto::golem::rib::DynamicIndexedResourceMethodFunctionReference {
893 resource,
894 resource_params: resource_params.into_iter().map(|x| x.into()).collect(),
895 method,
896 },
897 ),
898 DynamicParsedFunctionReference::IndexedResourceStaticMethod { resource, resource_params, method } => ProtoDynamicFunctionReference::IndexedResourceStaticMethod(
899 golem_api_grpc::proto::golem::rib::DynamicIndexedResourceStaticMethodFunctionReference {
900 resource,
901 resource_params: resource_params.into_iter().map(|x| x.into()).collect(),
902 method,
903 },
904 ),
905 DynamicParsedFunctionReference::IndexedResourceDrop { resource, resource_params } => ProtoDynamicFunctionReference::IndexedResourceDrop(
906 golem_api_grpc::proto::golem::rib::DynamicIndexedResourceDropFunctionReference {
907 resource,
908 resource_params: resource_params.into_iter().map(|x| x.into()).collect(),
909 },
910 ),
911 };
912
913 golem_api_grpc::proto::golem::rib::DynamicParsedFunctionReference {
914 function_reference: Some(function),
915 }
916 }
917 }
918
919 impl TryFrom<golem_api_grpc::proto::golem::rib::DynamicParsedFunctionReference>
920 for DynamicParsedFunctionReference
921 {
922 type Error = String;
923
924 fn try_from(
925 value: golem_api_grpc::proto::golem::rib::DynamicParsedFunctionReference,
926 ) -> Result<Self, Self::Error> {
927 let function = value
928 .function_reference
929 .ok_or("Missing function reference".to_string())?;
930
931 match function {
932 ProtoDynamicFunctionReference::Function(golem_api_grpc::proto::golem::rib::FunctionFunctionReference {
933 function
934 }) => {
935 Ok(Self::Function { function })
936 }
937 ProtoDynamicFunctionReference::RawResourceConstructor(golem_api_grpc::proto::golem::rib::RawResourceConstructorFunctionReference {
938 resource
939 }) => {
940 Ok(Self::RawResourceConstructor { resource })
941 }
942 ProtoDynamicFunctionReference::RawResourceMethod(golem_api_grpc::proto::golem::rib::RawResourceMethodFunctionReference {
943 resource,
944 method
945 }) => {
946 Ok(Self::RawResourceMethod { resource, method })
947 }
948 ProtoDynamicFunctionReference::RawResourceStaticMethod(golem_api_grpc::proto::golem::rib::RawResourceStaticMethodFunctionReference {
949 resource,
950 method
951 }) => {
952 Ok(Self::RawResourceStaticMethod { resource, method })
953 }
954 ProtoDynamicFunctionReference::RawResourceDrop(golem_api_grpc::proto::golem::rib::RawResourceDropFunctionReference {
955 resource
956 }) => {
957 Ok(Self::RawResourceDrop { resource })
958 }
959 ProtoDynamicFunctionReference::IndexedResourceConstructor(golem_api_grpc::proto::golem::rib::DynamicIndexedResourceConstructorFunctionReference {
960 resource,
961 resource_params
962 }) => {
963 let resource_params: Vec<Expr> =
964 resource_params.into_iter().map(Expr::try_from).collect::<Result<Vec<Expr>, String>>()?;
965
966 Ok(Self::IndexedResourceConstructor { resource, resource_params })
967 }
968 ProtoDynamicFunctionReference::IndexedResourceMethod(golem_api_grpc::proto::golem::rib::DynamicIndexedResourceMethodFunctionReference {
969 resource,
970 resource_params,
971 method
972 }) => {
973 let resource_params: Vec<Expr> =
974 resource_params.into_iter().map(Expr::try_from).collect::<Result<Vec<Expr>, String>>()?;
975
976 Ok(Self::IndexedResourceMethod { resource, resource_params, method })
977 }
978 ProtoDynamicFunctionReference::IndexedResourceStaticMethod(golem_api_grpc::proto::golem::rib::DynamicIndexedResourceStaticMethodFunctionReference {
979 resource,
980 resource_params,
981 method
982 }) => {
983 let resource_params: Vec<Expr> =
984 resource_params.into_iter().map(Expr::try_from).collect::<Result<Vec<Expr>, String>>()?;
985
986 Ok(Self::IndexedResourceStaticMethod { resource, resource_params, method })
987 }
988 ProtoDynamicFunctionReference::IndexedResourceDrop(golem_api_grpc::proto::golem::rib::DynamicIndexedResourceDropFunctionReference {
989 resource,
990 resource_params
991 }) => {
992 let resource_params: Vec<Expr> =
993 resource_params.into_iter().map(Expr::try_from).collect::<Result<Vec<Expr>, String>>()?;
994
995 Ok(Self::IndexedResourceDrop { resource, resource_params })
996 }
997 }
998 }
999 }
1000
1001 impl TryFrom<golem_api_grpc::proto::golem::rib::ParsedFunctionReference>
1002 for ParsedFunctionReference
1003 {
1004 type Error = String;
1005
1006 fn try_from(
1007 value: golem_api_grpc::proto::golem::rib::ParsedFunctionReference,
1008 ) -> Result<Self, Self::Error> {
1009 let function = value
1010 .function_reference
1011 .ok_or("Missing function".to_string())?;
1012 match function {
1013 golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::Function(golem_api_grpc::proto::golem::rib::FunctionFunctionReference {
1014 function
1015 }) => {
1016 Ok(Self::Function { function })
1017 }
1018 golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::RawResourceConstructor(golem_api_grpc::proto::golem::rib::RawResourceConstructorFunctionReference {
1019 resource
1020 }) => {
1021 Ok(Self::RawResourceConstructor { resource })
1022 }
1023 golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::RawResourceMethod(golem_api_grpc::proto::golem::rib::RawResourceMethodFunctionReference {
1024 resource,
1025 method
1026 }) => {
1027 Ok(Self::RawResourceMethod { resource, method })
1028 }
1029 golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::RawResourceStaticMethod(golem_api_grpc::proto::golem::rib::RawResourceStaticMethodFunctionReference {
1030 resource,
1031 method
1032 }) => {
1033 Ok(Self::RawResourceStaticMethod { resource, method })
1034 }
1035 golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::RawResourceDrop(golem_api_grpc::proto::golem::rib::RawResourceDropFunctionReference {
1036 resource
1037 }) => {
1038 Ok(Self::RawResourceDrop { resource })
1039 }
1040 golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::IndexedResourceConstructor(golem_api_grpc::proto::golem::rib::IndexedResourceConstructorFunctionReference {
1041 resource,
1042 resource_params
1043 }) => {
1044 Ok(Self::IndexedResourceConstructor {
1045 resource,
1046 resource_params,
1047 })
1048 }
1049 golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::IndexedResourceMethod(golem_api_grpc::proto::golem::rib::IndexedResourceMethodFunctionReference {
1050 resource,
1051 resource_params,
1052 method
1053 }) => {
1054 Ok(Self::IndexedResourceMethod {
1055 resource,
1056 resource_params,
1057 method,
1058 })
1059 }
1060 golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::IndexedResourceStaticMethod(golem_api_grpc::proto::golem::rib::IndexedResourceStaticMethodFunctionReference {
1061 resource,
1062 resource_params,
1063 method
1064 }) => {
1065 Ok(Self::IndexedResourceStaticMethod {
1066 resource,
1067 resource_params,
1068 method,
1069 })
1070 }
1071 golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::IndexedResourceDrop(golem_api_grpc::proto::golem::rib::IndexedResourceDropFunctionReference {
1072 resource,
1073 resource_params
1074 }) => {
1075 Ok(Self::IndexedResourceDrop {
1076 resource,
1077 resource_params,
1078 })
1079 }
1080 }
1081 }
1082 }
1083
1084 impl From<ParsedFunctionReference> for golem_api_grpc::proto::golem::rib::ParsedFunctionReference {
1085 fn from(value: ParsedFunctionReference) -> Self {
1086 let function = match value {
1087 ParsedFunctionReference::Function { function } => golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::Function(
1088 golem_api_grpc::proto::golem::rib::FunctionFunctionReference { function },
1089 ),
1090 ParsedFunctionReference::RawResourceConstructor { resource } => {
1091 golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::RawResourceConstructor(
1092 golem_api_grpc::proto::golem::rib::RawResourceConstructorFunctionReference {
1093 resource,
1094 },
1095 )
1096 }
1097 ParsedFunctionReference::RawResourceMethod { resource, method } => {
1098 golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::RawResourceMethod(
1099 golem_api_grpc::proto::golem::rib::RawResourceMethodFunctionReference {
1100 resource,
1101 method,
1102 },
1103 )
1104 }
1105 ParsedFunctionReference::RawResourceStaticMethod { resource, method } => {
1106 golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::RawResourceStaticMethod(
1107 golem_api_grpc::proto::golem::rib::RawResourceStaticMethodFunctionReference {
1108 resource,
1109 method,
1110 },
1111 )
1112 }
1113 ParsedFunctionReference::RawResourceDrop { resource } => golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::RawResourceDrop(
1114 golem_api_grpc::proto::golem::rib::RawResourceDropFunctionReference { resource },
1115 ),
1116 ParsedFunctionReference::IndexedResourceConstructor {
1117 resource,
1118 resource_params,
1119 } => golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::IndexedResourceConstructor(
1120 golem_api_grpc::proto::golem::rib::IndexedResourceConstructorFunctionReference {
1121 resource,
1122 resource_params,
1123 },
1124 ),
1125 ParsedFunctionReference::IndexedResourceMethod {
1126 resource,
1127 resource_params,
1128 method,
1129 } => golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::IndexedResourceMethod(
1130 golem_api_grpc::proto::golem::rib::IndexedResourceMethodFunctionReference {
1131 resource,
1132 resource_params,
1133 method,
1134 },
1135 ),
1136 ParsedFunctionReference::IndexedResourceStaticMethod {
1137 resource,
1138 resource_params,
1139 method,
1140 } => golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::IndexedResourceStaticMethod(
1141 golem_api_grpc::proto::golem::rib::IndexedResourceStaticMethodFunctionReference {
1142 resource,
1143 resource_params,
1144 method,
1145 },
1146 ),
1147 ParsedFunctionReference::IndexedResourceDrop {
1148 resource,
1149 resource_params,
1150 } => golem_api_grpc::proto::golem::rib::parsed_function_reference::FunctionReference::IndexedResourceDrop(
1151 golem_api_grpc::proto::golem::rib::IndexedResourceDropFunctionReference {
1152 resource,
1153 resource_params,
1154 },
1155 ),
1156 };
1157 golem_api_grpc::proto::golem::rib::ParsedFunctionReference {
1158 function_reference: Some(function),
1159 }
1160 }
1161 }
1162
1163 impl TryFrom<golem_api_grpc::proto::golem::rib::DynamicParsedFunctionName>
1164 for DynamicParsedFunctionName
1165 {
1166 type Error = String;
1167
1168 fn try_from(
1169 value: golem_api_grpc::proto::golem::rib::DynamicParsedFunctionName,
1170 ) -> Result<Self, Self::Error> {
1171 let site = ParsedFunctionSite::try_from(value.site.ok_or("Missing site".to_string())?)?;
1172 let function = DynamicParsedFunctionReference::try_from(
1173 value.function.ok_or("Missing function".to_string())?,
1174 )?;
1175 Ok(Self { site, function })
1176 }
1177 }
1178
1179 impl TryFrom<golem_api_grpc::proto::golem::rib::ParsedFunctionName> for ParsedFunctionName {
1180 type Error = String;
1181
1182 fn try_from(
1183 value: golem_api_grpc::proto::golem::rib::ParsedFunctionName,
1184 ) -> Result<Self, Self::Error> {
1185 let site = ParsedFunctionSite::try_from(value.site.ok_or("Missing site".to_string())?)?;
1186 let function = ParsedFunctionReference::try_from(
1187 value.function.ok_or("Missing function".to_string())?,
1188 )?;
1189 Ok(Self { site, function })
1190 }
1191 }
1192
1193 impl From<ParsedFunctionName> for golem_api_grpc::proto::golem::rib::ParsedFunctionName {
1194 fn from(value: ParsedFunctionName) -> Self {
1195 golem_api_grpc::proto::golem::rib::ParsedFunctionName {
1196 site: Some(value.site.into()),
1197 function: Some(value.function.into()),
1198 }
1199 }
1200 }
1201
1202 impl From<DynamicParsedFunctionName>
1203 for golem_api_grpc::proto::golem::rib::DynamicParsedFunctionName
1204 {
1205 fn from(value: DynamicParsedFunctionName) -> Self {
1206 golem_api_grpc::proto::golem::rib::DynamicParsedFunctionName {
1207 site: Some(value.site.into()),
1208 function: Some(value.function.into()),
1209 }
1210 }
1211 }
1212}
1213
1214#[cfg(test)]
1215mod function_name_tests {
1216 use super::{ParsedFunctionName, ParsedFunctionReference, ParsedFunctionSite, SemVer};
1217 use golem_wasm_ast::analysis::analysed_type::{field, record, u64};
1218 use golem_wasm_rpc::Value;
1219 use test_r::test;
1220
1221 #[test]
1222 fn parse_function_name_does_not_accept_partial_matches() {
1223 let result = ParsedFunctionName::parse("x:y/z");
1224 assert!(result.is_err());
1225 }
1226
1227 #[test]
1228 fn parse_function_name_global() {
1229 let parsed = ParsedFunctionName::parse("run-example").expect("Parsing failed");
1230 assert_eq!(parsed.site().interface_name(), None);
1231 assert_eq!(parsed.function().function_name(), "run-example");
1232 assert_eq!(
1233 parsed,
1234 ParsedFunctionName {
1235 site: ParsedFunctionSite::Global,
1236 function: ParsedFunctionReference::Function {
1237 function: "run-example".to_string()
1238 },
1239 }
1240 );
1241 }
1242
1243 #[test]
1244 fn parse_function_name_in_exported_interface_no_package() {
1245 let parsed = ParsedFunctionName::parse("interface.{fn1}").expect("Parsing failed");
1246 assert_eq!(
1247 parsed.site().interface_name(),
1248 Some("interface".to_string())
1249 );
1250 assert_eq!(parsed.function().function_name(), "fn1".to_string());
1251 assert_eq!(
1252 parsed,
1253 ParsedFunctionName {
1254 site: ParsedFunctionSite::Interface {
1255 name: "interface".to_string()
1256 },
1257 function: ParsedFunctionReference::Function {
1258 function: "fn1".to_string()
1259 },
1260 }
1261 );
1262 }
1263
1264 #[test]
1265 fn parse_function_name_in_exported_interface() {
1266 let parsed = ParsedFunctionName::parse("ns:name/interface.{fn1}").expect("Parsing failed");
1267 assert_eq!(
1268 parsed.site().interface_name(),
1269 Some("ns:name/interface".to_string())
1270 );
1271 assert_eq!(parsed.function().function_name(), "fn1".to_string());
1272 assert_eq!(
1273 parsed,
1274 ParsedFunctionName {
1275 site: ParsedFunctionSite::PackagedInterface {
1276 namespace: "ns".to_string(),
1277 package: "name".to_string(),
1278 interface: "interface".to_string(),
1279 version: None,
1280 },
1281 function: ParsedFunctionReference::Function {
1282 function: "fn1".to_string()
1283 },
1284 }
1285 );
1286 }
1287
1288 #[test]
1289 fn parse_function_name_in_versioned_exported_interface() {
1290 let parsed = ParsedFunctionName::parse("wasi:cli/run@0.2.0.{run}").expect("Parsing failed");
1291 assert_eq!(
1292 parsed.site().interface_name(),
1293 Some("wasi:cli/run@0.2.0".to_string())
1294 );
1295 assert_eq!(parsed.function().function_name(), "run".to_string());
1296 assert_eq!(
1297 parsed,
1298 ParsedFunctionName {
1299 site: ParsedFunctionSite::PackagedInterface {
1300 namespace: "wasi".to_string(),
1301 package: "cli".to_string(),
1302 interface: "run".to_string(),
1303 version: Some(SemVer(semver::Version::new(0, 2, 0))),
1304 },
1305 function: ParsedFunctionReference::Function {
1306 function: "run".to_string()
1307 },
1308 }
1309 );
1310 }
1311
1312 #[test]
1313 fn parse_function_name_constructor_syntax_sugar() {
1314 let parsed =
1315 ParsedFunctionName::parse("ns:name/interface.{resource1.new}").expect("Parsing failed");
1316 assert_eq!(
1317 parsed.site().interface_name(),
1318 Some("ns:name/interface".to_string())
1319 );
1320 assert_eq!(
1321 parsed.function().function_name(),
1322 "[constructor]resource1".to_string()
1323 );
1324 assert_eq!(
1325 parsed,
1326 ParsedFunctionName {
1327 site: ParsedFunctionSite::PackagedInterface {
1328 namespace: "ns".to_string(),
1329 package: "name".to_string(),
1330 interface: "interface".to_string(),
1331 version: None,
1332 },
1333 function: ParsedFunctionReference::RawResourceConstructor {
1334 resource: "resource1".to_string()
1335 },
1336 }
1337 );
1338 }
1339
1340 #[test]
1341 fn parse_function_name_constructor() {
1342 let parsed = ParsedFunctionName::parse("ns:name/interface.{[constructor]resource1}")
1343 .expect("Parsing failed");
1344 assert_eq!(
1345 parsed.site().interface_name(),
1346 Some("ns:name/interface".to_string())
1347 );
1348 assert_eq!(
1349 parsed.function().function_name(),
1350 "[constructor]resource1".to_string()
1351 );
1352 assert_eq!(
1353 parsed,
1354 ParsedFunctionName {
1355 site: ParsedFunctionSite::PackagedInterface {
1356 namespace: "ns".to_string(),
1357 package: "name".to_string(),
1358 interface: "interface".to_string(),
1359 version: None,
1360 },
1361 function: ParsedFunctionReference::RawResourceConstructor {
1362 resource: "resource1".to_string()
1363 },
1364 }
1365 );
1366 }
1367
1368 #[test]
1369 fn parse_function_name_indexed_constructor_1() {
1370 let parsed = ParsedFunctionName::parse("ns:name/interface.{resource1().new}")
1371 .expect("Parsing failed");
1372 assert_eq!(
1373 parsed.site().interface_name(),
1374 Some("ns:name/interface".to_string())
1375 );
1376 assert_eq!(
1377 parsed.function().function_name(),
1378 "[constructor]resource1".to_string()
1379 );
1380 assert!(parsed.function().is_indexed_resource());
1381 assert_eq!(parsed.function().raw_resource_params(), Some(&vec![]));
1382 assert_eq!(
1383 parsed,
1384 ParsedFunctionName {
1385 site: ParsedFunctionSite::PackagedInterface {
1386 namespace: "ns".to_string(),
1387 package: "name".to_string(),
1388 interface: "interface".to_string(),
1389 version: None,
1390 },
1391 function: ParsedFunctionReference::IndexedResourceConstructor {
1392 resource: "resource1".to_string(),
1393 resource_params: vec![],
1394 },
1395 }
1396 );
1397 }
1398
1399 #[test]
1400 fn parse_function_name_indexed_constructor_2() {
1401 let parsed =
1402 ParsedFunctionName::parse("ns:name/interface.{resource1(\"hello\", 1, true).new}")
1403 .expect("Parsing failed");
1404 assert_eq!(
1405 parsed.site().interface_name(),
1406 Some("ns:name/interface".to_string())
1407 );
1408 assert_eq!(
1409 parsed.function().function_name(),
1410 "[constructor]resource1".to_string()
1411 );
1412 assert!(parsed.function().is_indexed_resource());
1413 assert_eq!(
1414 parsed.function().raw_resource_params(),
1415 Some(&vec![
1416 "\"hello\"".to_string(),
1417 "1".to_string(),
1418 "true".to_string(),
1419 ])
1420 );
1421 assert_eq!(
1422 parsed,
1423 ParsedFunctionName {
1424 site: ParsedFunctionSite::PackagedInterface {
1425 namespace: "ns".to_string(),
1426 package: "name".to_string(),
1427 interface: "interface".to_string(),
1428 version: None,
1429 },
1430 function: ParsedFunctionReference::IndexedResourceConstructor {
1431 resource: "resource1".to_string(),
1432 resource_params: vec![
1433 "\"hello\"".to_string(),
1434 "1".to_string(),
1435 "true".to_string(),
1436 ],
1437 },
1438 },
1439 );
1440 }
1441
1442 #[test]
1443 fn parse_function_name_indexed_constructor_3() {
1444 let parsed = ParsedFunctionName::parse(
1445 "ns:name/interface.{resource1(\"hello\", { field-a: some(1) }).new}",
1446 )
1447 .expect("Parsing failed");
1448 assert_eq!(
1449 parsed.site().interface_name(),
1450 Some("ns:name/interface".to_string())
1451 );
1452 assert_eq!(
1453 parsed.function().function_name(),
1454 "[constructor]resource1".to_string()
1455 );
1456 assert!(parsed.function().is_indexed_resource());
1457 assert_eq!(
1458 parsed.function().raw_resource_params(),
1459 Some(&vec![
1460 "\"hello\"".to_string(),
1461 "{field-a: some(1)}".to_string(),
1462 ])
1463 );
1464 assert_eq!(
1465 parsed,
1466 ParsedFunctionName {
1467 site: ParsedFunctionSite::PackagedInterface {
1468 namespace: "ns".to_string(),
1469 package: "name".to_string(),
1470 interface: "interface".to_string(),
1471 version: None,
1472 },
1473 function: ParsedFunctionReference::IndexedResourceConstructor {
1474 resource: "resource1".to_string(),
1475 resource_params: vec![
1476 "\"hello\"".to_string(),
1477 "{field-a: some(1)}".to_string(),
1478 ],
1479 },
1480 },
1481 );
1482 }
1483
1484 #[test]
1485 fn parse_function_name_indexed_method() {
1486 let parsed = ParsedFunctionName::parse(
1487 "ns:name/interface.{resource1(\"hello\", { field-a: some(1) }).something}",
1488 )
1489 .expect("Parsing failed");
1490 assert_eq!(
1491 parsed.site().interface_name(),
1492 Some("ns:name/interface".to_string())
1493 );
1494 assert_eq!(
1495 parsed.function().function_name(),
1496 "[method]resource1.something".to_string()
1497 );
1498 assert!(parsed.function().is_indexed_resource());
1499 assert_eq!(
1500 parsed.function().raw_resource_params(),
1501 Some(&vec![
1502 "\"hello\"".to_string(),
1503 "{field-a: some(1)}".to_string(),
1504 ])
1505 );
1506 assert_eq!(
1507 parsed.function().resource_method_name(),
1508 Some("something".to_string())
1509 );
1510 assert_eq!(
1511 parsed,
1512 ParsedFunctionName {
1513 site: ParsedFunctionSite::PackagedInterface {
1514 namespace: "ns".to_string(),
1515 package: "name".to_string(),
1516 interface: "interface".to_string(),
1517 version: None,
1518 },
1519 function: ParsedFunctionReference::IndexedResourceMethod {
1520 resource: "resource1".to_string(),
1521 resource_params: vec![
1522 "\"hello\"".to_string(),
1523 "{field-a: some(1)}".to_string(),
1524 ],
1525 method: "something".to_string(),
1526 },
1527 },
1528 );
1529 }
1530
1531 #[test]
1532 fn parse_function_name_indexed_static_method() {
1533 let parsed = ParsedFunctionName::parse(
1534 "ns:name/interface.{[static]resource1(\"hello\", { field-a: some(1) }).something}",
1535 )
1536 .expect("Parsing failed");
1537 assert_eq!(
1538 parsed.site().interface_name(),
1539 Some("ns:name/interface".to_string())
1540 );
1541 assert_eq!(
1542 parsed.function().function_name(),
1543 "[static]resource1.something".to_string()
1544 );
1545 assert!(parsed.function().is_indexed_resource());
1546 assert_eq!(
1547 parsed.function().raw_resource_params(),
1548 Some(&vec![
1549 "\"hello\"".to_string(),
1550 "{field-a: some(1)}".to_string(),
1551 ])
1552 );
1553 assert_eq!(
1554 parsed.function().resource_method_name(),
1555 Some("something".to_string())
1556 );
1557 assert_eq!(
1558 parsed,
1559 ParsedFunctionName {
1560 site: ParsedFunctionSite::PackagedInterface {
1561 namespace: "ns".to_string(),
1562 package: "name".to_string(),
1563 interface: "interface".to_string(),
1564 version: None,
1565 },
1566 function: ParsedFunctionReference::IndexedResourceStaticMethod {
1567 resource: "resource1".to_string(),
1568 resource_params: vec![
1569 "\"hello\"".to_string(),
1570 "{field-a: some(1)}".to_string(),
1571 ],
1572 method: "something".to_string(),
1573 },
1574 },
1575 );
1576 }
1577
1578 #[test]
1579 fn parse_function_name_method_syntax_sugar() {
1580 let parsed = ParsedFunctionName::parse("ns:name/interface.{resource1.do-something}")
1581 .expect("Parsing failed");
1582 assert_eq!(
1583 parsed.site().interface_name(),
1584 Some("ns:name/interface".to_string())
1585 );
1586 assert_eq!(
1587 parsed.function().function_name(),
1588 "[method]resource1.do-something".to_string()
1589 );
1590 assert_eq!(
1591 parsed,
1592 ParsedFunctionName {
1593 site: ParsedFunctionSite::PackagedInterface {
1594 namespace: "ns".to_string(),
1595 package: "name".to_string(),
1596 interface: "interface".to_string(),
1597 version: None,
1598 },
1599 function: ParsedFunctionReference::RawResourceMethod {
1600 resource: "resource1".to_string(),
1601 method: "do-something".to_string(),
1602 },
1603 }
1604 );
1605 }
1606
1607 #[test]
1608 fn parse_function_name_method() {
1609 let parsed =
1610 ParsedFunctionName::parse("ns:name/interface.{[method]resource1.do-something}")
1611 .expect("Parsing failed");
1612 assert_eq!(
1613 parsed.site().interface_name(),
1614 Some("ns:name/interface".to_string())
1615 );
1616 assert_eq!(
1617 parsed.function().function_name(),
1618 "[method]resource1.do-something".to_string()
1619 );
1620 assert_eq!(
1621 parsed,
1622 ParsedFunctionName {
1623 site: ParsedFunctionSite::PackagedInterface {
1624 namespace: "ns".to_string(),
1625 package: "name".to_string(),
1626 interface: "interface".to_string(),
1627 version: None,
1628 },
1629 function: ParsedFunctionReference::RawResourceMethod {
1630 resource: "resource1".to_string(),
1631 method: "do-something".to_string(),
1632 },
1633 }
1634 );
1635 }
1636
1637 #[test]
1638 fn parse_function_name_static_method_syntax_sugar() {
1639 let parsed = ParsedFunctionName::parse("ns:name/interface.{resource1.do-something-static}")
1642 .expect("Parsing failed")
1643 .method_as_static()
1644 .unwrap();
1645 assert_eq!(
1646 parsed.site().interface_name(),
1647 Some("ns:name/interface".to_string())
1648 );
1649 assert_eq!(
1650 parsed.function().function_name(),
1651 "[static]resource1.do-something-static".to_string()
1652 );
1653 assert_eq!(
1654 parsed,
1655 ParsedFunctionName {
1656 site: ParsedFunctionSite::PackagedInterface {
1657 namespace: "ns".to_string(),
1658 package: "name".to_string(),
1659 interface: "interface".to_string(),
1660 version: None,
1661 },
1662 function: ParsedFunctionReference::RawResourceStaticMethod {
1663 resource: "resource1".to_string(),
1664 method: "do-something-static".to_string(),
1665 },
1666 }
1667 );
1668 }
1669
1670 #[test]
1671 fn parse_function_name_static() {
1672 let parsed =
1673 ParsedFunctionName::parse("ns:name/interface.{[static]resource1.do-something-static}")
1674 .expect("Parsing failed");
1675 assert_eq!(
1676 parsed.site().interface_name(),
1677 Some("ns:name/interface".to_string())
1678 );
1679 assert_eq!(
1680 parsed.function().function_name(),
1681 "[static]resource1.do-something-static".to_string()
1682 );
1683 assert_eq!(
1684 parsed,
1685 ParsedFunctionName {
1686 site: ParsedFunctionSite::PackagedInterface {
1687 namespace: "ns".to_string(),
1688 package: "name".to_string(),
1689 interface: "interface".to_string(),
1690 version: None,
1691 },
1692 function: ParsedFunctionReference::RawResourceStaticMethod {
1693 resource: "resource1".to_string(),
1694 method: "do-something-static".to_string(),
1695 },
1696 }
1697 );
1698 }
1699
1700 #[test]
1701 fn parse_function_name_drop_syntax_sugar() {
1702 let parsed = ParsedFunctionName::parse("ns:name/interface.{resource1.drop}")
1703 .expect("Parsing failed");
1704 assert_eq!(
1705 parsed.site().interface_name(),
1706 Some("ns:name/interface".to_string())
1707 );
1708 assert_eq!(
1709 parsed.function().function_name(),
1710 "[drop]resource1".to_string()
1711 );
1712 assert_eq!(
1713 parsed,
1714 ParsedFunctionName {
1715 site: ParsedFunctionSite::PackagedInterface {
1716 namespace: "ns".to_string(),
1717 package: "name".to_string(),
1718 interface: "interface".to_string(),
1719 version: None,
1720 },
1721 function: ParsedFunctionReference::RawResourceDrop {
1722 resource: "resource1".to_string()
1723 },
1724 }
1725 );
1726 }
1727
1728 #[test]
1729 fn parse_function_name_indexed_drop_1() {
1730 let parsed = ParsedFunctionName::parse("ns:name/interface.{resource1().drop}")
1731 .expect("Parsing failed");
1732 assert_eq!(
1733 parsed.site().interface_name(),
1734 Some("ns:name/interface".to_string())
1735 );
1736 assert_eq!(
1737 parsed.function().function_name(),
1738 "[drop]resource1".to_string()
1739 );
1740 assert!(parsed.function().is_indexed_resource());
1741 assert_eq!(parsed.function().raw_resource_params(), Some(&vec![]));
1742 assert_eq!(
1743 parsed,
1744 ParsedFunctionName {
1745 site: ParsedFunctionSite::PackagedInterface {
1746 namespace: "ns".to_string(),
1747 package: "name".to_string(),
1748 interface: "interface".to_string(),
1749 version: None,
1750 },
1751 function: ParsedFunctionReference::IndexedResourceDrop {
1752 resource: "resource1".to_string(),
1753 resource_params: vec![],
1754 },
1755 }
1756 )
1757 }
1758
1759 #[test]
1760 fn parse_function_name_indexed_drop_2() {
1761 let parsed =
1762 ParsedFunctionName::parse("ns:name/interface.{resource1(\"hello\", 1, true).drop}")
1763 .expect("Parsing failed");
1764 assert_eq!(
1765 parsed.site().interface_name(),
1766 Some("ns:name/interface".to_string())
1767 );
1768 assert_eq!(
1769 parsed.function().function_name(),
1770 "[drop]resource1".to_string()
1771 );
1772 assert!(parsed.function().is_indexed_resource());
1773 assert_eq!(
1774 parsed.function().raw_resource_params(),
1775 Some(&vec![
1776 "\"hello\"".to_string(),
1777 "1".to_string(),
1778 "true".to_string(),
1779 ])
1780 );
1781 assert_eq!(
1782 parsed,
1783 ParsedFunctionName {
1784 site: ParsedFunctionSite::PackagedInterface {
1785 namespace: "ns".to_string(),
1786 package: "name".to_string(),
1787 interface: "interface".to_string(),
1788 version: None,
1789 },
1790 function: ParsedFunctionReference::IndexedResourceDrop {
1791 resource: "resource1".to_string(),
1792 resource_params: vec![
1793 "\"hello\"".to_string(),
1794 "1".to_string(),
1795 "true".to_string(),
1796 ],
1797 },
1798 }
1799 );
1800 }
1801
1802 #[test]
1803 fn parse_function_name_indexed_drop_3() {
1804 let parsed = ParsedFunctionName::parse(
1805 "ns:name/interface.{resource1(\"hello\", { field-a: some(1) }).drop}",
1806 )
1807 .expect("Parsing failed");
1808 assert_eq!(
1809 parsed.site().interface_name(),
1810 Some("ns:name/interface".to_string())
1811 );
1812 assert_eq!(
1813 parsed.function().function_name(),
1814 "[drop]resource1".to_string()
1815 );
1816 assert!(parsed.function().is_indexed_resource());
1817 assert_eq!(
1818 parsed.function().raw_resource_params(),
1819 Some(&vec![
1820 "\"hello\"".to_string(),
1821 "{field-a: some(1)}".to_string(),
1822 ])
1823 );
1824 assert_eq!(
1825 parsed,
1826 ParsedFunctionName {
1827 site: ParsedFunctionSite::PackagedInterface {
1828 namespace: "ns".to_string(),
1829 package: "name".to_string(),
1830 interface: "interface".to_string(),
1831 version: None,
1832 },
1833 function: ParsedFunctionReference::IndexedResourceDrop {
1834 resource: "resource1".to_string(),
1835 resource_params: vec![
1836 "\"hello\"".to_string(),
1837 "{field-a: some(1)}".to_string(),
1838 ],
1839 },
1840 },
1841 );
1842 }
1843
1844 #[test]
1845 fn parse_function_name_drop() {
1846 let parsed = ParsedFunctionName::parse("ns:name/interface.{[drop]resource1}")
1847 .expect("Parsing failed");
1848 assert_eq!(
1849 parsed.site().interface_name(),
1850 Some("ns:name/interface".to_string())
1851 );
1852 assert_eq!(
1853 parsed.function().function_name(),
1854 "[drop]resource1".to_string()
1855 );
1856 assert_eq!(
1857 parsed,
1858 ParsedFunctionName {
1859 site: ParsedFunctionSite::PackagedInterface {
1860 namespace: "ns".to_string(),
1861 package: "name".to_string(),
1862 interface: "interface".to_string(),
1863 version: None,
1864 },
1865 function: ParsedFunctionReference::RawResourceDrop {
1866 resource: "resource1".to_string()
1867 },
1868 }
1869 );
1870 }
1871
1872 fn round_trip_function_name_parse(input: &str) {
1873 let parsed = ParsedFunctionName::parse(input)
1874 .unwrap_or_else(|_| panic!("Input Parsing failed for {input}"));
1875 let parsed_written =
1876 ParsedFunctionName::parse(parsed.to_string()).expect("Round-trip parsing failed");
1877 assert_eq!(parsed, parsed_written);
1878 }
1879
1880 #[test]
1881 fn test_parsed_function_name_display() {
1882 round_trip_function_name_parse("run-example");
1883 round_trip_function_name_parse("interface.{fn1}");
1884 round_trip_function_name_parse("wasi:cli/run@0.2.0.{run}");
1885 round_trip_function_name_parse("ns:name/interface.{resource1.new}");
1886 round_trip_function_name_parse("ns:name/interface.{[constructor]resource1}");
1887 round_trip_function_name_parse("ns:name/interface.{resource1().new}");
1888 round_trip_function_name_parse("ns:name/interface.{resource1(\"hello\", 1, true).new}");
1889 round_trip_function_name_parse(
1890 "ns:name/interface.{resource1(\"hello\", { field-a: some(1) }).new}",
1891 );
1892 round_trip_function_name_parse("ns:name/interface.{resource1.do-something}");
1893 round_trip_function_name_parse(
1894 "ns:name/interface.{resource1(\"hello\", 1, true).do-something}",
1895 );
1896 round_trip_function_name_parse(
1897 "ns:name/interface.{resource1(\"hello\", 1, { field-a: some(1) }).do-something}",
1898 );
1899 round_trip_function_name_parse("ns:name/interface.{[static]resource1.do-something-static}");
1900 round_trip_function_name_parse(
1901 "ns:name/interface.{[static]resource1(\"hello\", 1, true).do-something-static}",
1902 );
1903 round_trip_function_name_parse("ns:name/interface.{[static]resource1(\"hello\", 1, { field-a: some(1) }).do-something-static}");
1904 round_trip_function_name_parse("ns:name/interface.{resource1.drop}");
1905 round_trip_function_name_parse("ns:name/interface.{resource1().drop}");
1906 round_trip_function_name_parse("ns:name/interface.{resource1(\"hello\", 1, true).drop}");
1907 round_trip_function_name_parse(
1908 "ns:name/interface.{resource1(\"hello\", { field-a: some(1) }).drop}",
1909 );
1910 round_trip_function_name_parse("ns:name/interface.{[drop]resource1}");
1911 }
1912
1913 #[test]
1914 fn test_parsed_function_name_complex_resource_args() {
1915 round_trip_function_name_parse(
1916 r#"golem:api/oplog-processor@1.1.0-rc1.{processor({ account-id: { value: "-1" } }, { high-bits: 11637111831105389641, low-bits: 11277240687824975272 }, []).process}"#,
1917 )
1918 }
1919
1920 #[test]
1921 fn test_parsed_function_name_complex_resource_args_large_nums() {
1922 let parsed = ParsedFunctionName::parse(r#"golem:api/oplog-processor@1.1.0-rc1.{processor({ high-bits: 18389549593665948372, low-bits: 12287617583649128209 }).process}"#).expect("Input Parsing failed");
1923 let args = parsed
1924 .function
1925 .resource_params(&[record(vec![
1926 field("high-bits", u64()),
1927 field("low-bits", u64()),
1928 ])])
1929 .expect("Resource params parsing failed")
1930 .expect("Resource params not found");
1931 let nums = if let Value::Record(nums) = &args[0].value {
1932 nums.clone()
1933 } else {
1934 panic!("Expected record")
1935 };
1936
1937 assert_eq!(
1938 nums,
1939 vec![
1940 Value::U64(18389549593665948372u64),
1941 Value::U64(12287617583649128209u64),
1942 ]
1943 )
1944 }
1945}