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