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