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