rib/
function_name.rs

1// Copyright 2024-2025 Golem Cloud
2//
3// Licensed under the Golem Source License v1.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://license.golem.cloud/LICENSE
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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// DynamicParsedFunctionName is different from ParsedFunctionName.
500// In `DynamicParsedFunctionName` the resource parameters are `Expr` (Rib) while they are `String`
501// in `ParsedFunctionName`.
502// `Expr` implies the real values are yet to be computed, while `String`
503// in ParsedFunctionName is a textual representation of the evaluated values.
504// `Examples`:
505// `DynamicParsedFunctionName` : ns:name/interface.{resource1(identifier1, { field-a: some(identifier2) }).new}
506// `ParsedFunctionName` : ns:name/interface.{resource1("foo", { field-a: some("bar") }).new}
507#[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    // Usually resource name in the real metadata consist of prefixes such as [constructor]
535    // However, the one obtained through the dynamic-parsed-function-name is simple without these prefix
536    pub fn resource_name_simplified(&self) -> Option<String> {
537        self.to_parsed_function_name()
538            .function
539            .resource_name()
540            .cloned()
541    }
542
543    // Usually resource method in the real metadata consist of prefixes such as [method]
544    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    //
555    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        // Note: the syntax sugared version cannot distinguish between method and static - so we need to check the actual existence of
1572        // the function and fallback.
1573        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}