rib/
call_type.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::{ComponentDependencyKey, DynamicParsedFunctionName, Expr};
16use crate::{FullyQualifiedResourceConstructor, VariableId};
17use std::fmt::Display;
18
19#[derive(Debug, Hash, PartialEq, Eq, Clone, Ord, PartialOrd)]
20pub enum CallType {
21    Function {
22        component_info: Option<ComponentDependencyKey>,
23        // as compilation progress the function call is expected to a instance_identifier
24        // and will be always `Some`.
25        instance_identifier: Option<Box<InstanceIdentifier>>,
26        // TODO; a dynamic-parsed-function-name can be replaced by ParsedFunctionName
27        // after the introduction of non-lazy resource constructor.
28        function_name: DynamicParsedFunctionName,
29    },
30    VariantConstructor(String),
31    EnumConstructor(String),
32    InstanceCreation(InstanceCreationType),
33}
34
35// InstanceIdentifier holds the variables that are used to identify a worker or resource instance.
36// Unlike InstanceCreationType, this type can be formed only after the instance is inferred
37#[derive(Debug, Hash, PartialEq, Eq, Clone, Ord, PartialOrd)]
38pub enum InstanceIdentifier {
39    WitWorker {
40        variable_id: Option<VariableId>,
41        worker_name: Option<Box<Expr>>,
42    },
43
44    WitResource {
45        variable_id: Option<VariableId>,
46        worker_name: Option<Box<Expr>>,
47        resource_name: String,
48    },
49}
50
51impl InstanceIdentifier {
52    pub fn worker_name_mut(&mut self) -> Option<&mut Box<Expr>> {
53        match self {
54            InstanceIdentifier::WitWorker { worker_name, .. } => worker_name.as_mut(),
55            InstanceIdentifier::WitResource { worker_name, .. } => worker_name.as_mut(),
56        }
57    }
58    pub fn worker_name(&self) -> Option<&Expr> {
59        match self {
60            InstanceIdentifier::WitWorker { worker_name, .. } => worker_name.as_deref(),
61            InstanceIdentifier::WitResource { worker_name, .. } => worker_name.as_deref(),
62        }
63    }
64}
65
66#[derive(Debug, Hash, PartialEq, Eq, Clone, Ord, PartialOrd)]
67pub enum InstanceCreationType {
68    // A wit worker instance can be created without another module
69    WitWorker {
70        component_info: Option<ComponentDependencyKey>,
71        worker_name: Option<Box<Expr>>,
72    },
73    // an instance type of the type wit-resource can only be part of
74    // another instance (we call it module), which can be theoretically only be
75    // a worker, but we don't restrict this in types, such that it will easily
76    // handle nested wit resources
77    WitResource {
78        component_info: Option<ComponentDependencyKey>,
79        // this module identifier during resource creation will be always a worker module, but we don't necessarily restrict
80        // i.e, we do allow nested resource construction
81        module: Option<InstanceIdentifier>,
82        resource_name: FullyQualifiedResourceConstructor,
83    },
84}
85
86impl InstanceCreationType {
87    pub fn worker_name(&self) -> Option<Expr> {
88        match self {
89            InstanceCreationType::WitWorker { worker_name, .. } => worker_name.as_deref().cloned(),
90            InstanceCreationType::WitResource { module, .. } => {
91                let r = module.as_ref().and_then(|m| m.worker_name());
92                r.cloned()
93            }
94        }
95    }
96}
97
98impl CallType {
99    pub fn function_name(&self) -> Option<DynamicParsedFunctionName> {
100        match self {
101            CallType::Function { function_name, .. } => Some(function_name.clone()),
102            _ => None,
103        }
104    }
105    pub fn worker_expr(&self) -> Option<&Expr> {
106        match self {
107            CallType::Function {
108                instance_identifier,
109                ..
110            } => {
111                let module = instance_identifier.as_ref()?;
112                module.worker_name()
113            }
114            _ => None,
115        }
116    }
117
118    pub fn function_call(
119        function: DynamicParsedFunctionName,
120        component_info: Option<ComponentDependencyKey>,
121    ) -> CallType {
122        CallType::Function {
123            instance_identifier: None,
124            function_name: function,
125            component_info,
126        }
127    }
128
129    pub fn function_call_with_worker(
130        module: InstanceIdentifier,
131        function: DynamicParsedFunctionName,
132        component_info: Option<ComponentDependencyKey>,
133    ) -> CallType {
134        CallType::Function {
135            instance_identifier: Some(Box::new(module)),
136            function_name: function,
137            component_info,
138        }
139    }
140
141    pub fn is_resource_method(&self) -> bool {
142        match self {
143            CallType::Function { function_name, .. } => function_name
144                .to_parsed_function_name()
145                .function
146                .resource_method_name()
147                .is_some(),
148            _ => false,
149        }
150    }
151}
152
153impl Display for CallType {
154    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
155        match self {
156            CallType::Function { function_name, .. } => write!(f, "{function_name}"),
157            CallType::VariantConstructor(name) => write!(f, "{name}"),
158            CallType::EnumConstructor(name) => write!(f, "{name}"),
159            CallType::InstanceCreation(instance_creation_type) => match instance_creation_type {
160                InstanceCreationType::WitWorker { .. } => {
161                    write!(f, "instance")
162                }
163                InstanceCreationType::WitResource { resource_name, .. } => {
164                    write!(f, "{}", resource_name.resource_name)
165                }
166            },
167        }
168    }
169}
170
171#[cfg(feature = "protobuf")]
172mod protobuf {
173    use crate::call_type::{CallType, InstanceCreationType};
174    use crate::FullyQualifiedResourceConstructor;
175    use crate::{ComponentDependencyKey, DynamicParsedFunctionName, Expr, ParsedFunctionName};
176    use golem_api_grpc::proto::golem::rib::WorkerInstance;
177
178    impl TryFrom<golem_api_grpc::proto::golem::rib::ComponentDependencyKey> for ComponentDependencyKey {
179        type Error = String;
180
181        fn try_from(
182            value: golem_api_grpc::proto::golem::rib::ComponentDependencyKey,
183        ) -> Result<Self, Self::Error> {
184            let component_name = value.component_name;
185            let component_id = value.value.ok_or("Missing component id")?;
186            let component_version = value.component_version;
187
188            let root_package_name = value.root_package_name;
189
190            let root_package_version = value.root_package_version;
191
192            Ok(ComponentDependencyKey {
193                component_name,
194                component_id: component_id.into(),
195                component_version,
196                root_package_name,
197                root_package_version,
198            })
199        }
200    }
201
202    impl From<ComponentDependencyKey> for golem_api_grpc::proto::golem::rib::ComponentDependencyKey {
203        fn from(value: ComponentDependencyKey) -> Self {
204            golem_api_grpc::proto::golem::rib::ComponentDependencyKey {
205                component_name: value.component_name,
206                component_version: value.component_version,
207                value: Some(value.component_id.into()),
208                root_package_name: value.root_package_name,
209                root_package_version: value.root_package_version,
210            }
211        }
212    }
213
214    impl TryFrom<golem_api_grpc::proto::golem::rib::InstanceCreationType> for InstanceCreationType {
215        type Error = String;
216        fn try_from(
217            value: golem_api_grpc::proto::golem::rib::InstanceCreationType,
218        ) -> Result<Self, Self::Error> {
219            match value.kind.ok_or("Missing instance creation kind")? {
220                golem_api_grpc::proto::golem::rib::instance_creation_type::Kind::Worker(
221                    worker_instance,
222                ) => {
223                    let worker_name = worker_instance
224                        .worker_name
225                        .map(|w| Expr::try_from(*w))
226                        .transpose()?
227                        .map(Box::new);
228
229                    Ok(InstanceCreationType::WitWorker {
230                        component_info: None,
231                        worker_name,
232                    })
233                }
234                golem_api_grpc::proto::golem::rib::instance_creation_type::Kind::Resource(
235                    resource_instance,
236                ) => {
237                    let resource_constructor_proto = resource_instance
238                        .resource_name
239                        .ok_or("Missing resource name")?;
240                    let resource_name =
241                        FullyQualifiedResourceConstructor::try_from(resource_constructor_proto)?;
242
243                    let component_info = resource_instance
244                        .component
245                        .map(ComponentDependencyKey::try_from)
246                        .transpose()?;
247
248                    Ok(InstanceCreationType::WitResource {
249                        component_info,
250                        module: None,
251                        resource_name,
252                    })
253                }
254            }
255        }
256    }
257
258    impl From<InstanceCreationType> for golem_api_grpc::proto::golem::rib::InstanceCreationType {
259        fn from(value: InstanceCreationType) -> Self {
260            match value {
261                InstanceCreationType::WitWorker { component_info, .. } => {
262                    golem_api_grpc::proto::golem::rib::InstanceCreationType {
263                        kind: Some(golem_api_grpc::proto::golem::rib::instance_creation_type::Kind::Worker(Box::new(WorkerInstance {
264                            component: component_info.map(golem_api_grpc::proto::golem::rib::ComponentDependencyKey::from),
265                            worker_name: None
266                        }))),
267                    }
268                }
269                InstanceCreationType::WitResource { component_info, resource_name, .. } => {
270                    golem_api_grpc::proto::golem::rib::InstanceCreationType {
271                        kind: Some(golem_api_grpc::proto::golem::rib::instance_creation_type::Kind::Resource(Box::new(golem_api_grpc::proto::golem::rib::ResourceInstanceWithWorkerName {
272                            component: component_info.map(golem_api_grpc::proto::golem::rib::ComponentDependencyKey::from),
273                            worker_name: None,
274                            resource_name: Some(golem_api_grpc::proto::golem::rib::FullyQualifiedResourceConstructor::from(resource_name)),
275                        }))),
276                    }
277                }
278            }
279        }
280    }
281
282    impl TryFrom<golem_api_grpc::proto::golem::rib::CallType> for CallType {
283        type Error = String;
284        fn try_from(
285            value: golem_api_grpc::proto::golem::rib::CallType,
286        ) -> Result<Self, Self::Error> {
287            let invocation = value.name.ok_or("Missing name of invocation")?;
288            match invocation {
289                golem_api_grpc::proto::golem::rib::call_type::Name::Parsed(name) => {
290                    Ok(CallType::Function {
291                        component_info: None,
292                        function_name: DynamicParsedFunctionName::try_from(name)?,
293                        instance_identifier: None,
294                    })
295                }
296                golem_api_grpc::proto::golem::rib::call_type::Name::VariantConstructor(name) => {
297                    Ok(CallType::VariantConstructor(name))
298                }
299                golem_api_grpc::proto::golem::rib::call_type::Name::EnumConstructor(name) => {
300                    Ok(CallType::EnumConstructor(name))
301                }
302
303                golem_api_grpc::proto::golem::rib::call_type::Name::InstanceCreation(
304                    instance_creation,
305                ) => {
306                    let instance_creation = InstanceCreationType::try_from(*instance_creation)?;
307                    Ok(CallType::InstanceCreation(instance_creation))
308                }
309            }
310        }
311    }
312
313    impl From<CallType> for golem_api_grpc::proto::golem::rib::CallType {
314        fn from(value: CallType) -> Self {
315            match value {
316                CallType::Function {
317                    function_name,
318                    ..
319                } => golem_api_grpc::proto::golem::rib::CallType {
320                    name: Some(golem_api_grpc::proto::golem::rib::call_type::Name::Parsed(
321                        function_name.into(),
322                    )),
323                },
324                CallType::VariantConstructor(name) => golem_api_grpc::proto::golem::rib::CallType {
325                    name: Some(
326                        golem_api_grpc::proto::golem::rib::call_type::Name::VariantConstructor(
327                            name,
328                        ),
329                    ),
330                },
331                CallType::EnumConstructor(name) => golem_api_grpc::proto::golem::rib::CallType {
332                    name: Some(
333                        golem_api_grpc::proto::golem::rib::call_type::Name::EnumConstructor(name),
334                    ),
335                },
336                CallType::InstanceCreation(instance_creation) => {
337                    match instance_creation {
338                        InstanceCreationType::WitWorker { worker_name , component_info} => {
339                            golem_api_grpc::proto::golem::rib::CallType {
340                                name:  Some(golem_api_grpc::proto::golem::rib::call_type::Name::InstanceCreation(
341                                    Box::new(golem_api_grpc::proto::golem::rib::InstanceCreationType {
342                                        kind: Some(golem_api_grpc::proto::golem::rib::instance_creation_type::Kind::Worker(Box::new(WorkerInstance {
343                                            component: component_info.map(golem_api_grpc::proto::golem::rib::ComponentDependencyKey::from),
344                                            worker_name: worker_name.map(|w| Box::new(golem_api_grpc::proto::golem::rib::Expr::from(*w))),
345                                        }))),
346                                    })
347                                )),
348                            }
349                        }
350                        InstanceCreationType::WitResource { resource_name, component_info, .. } => {
351                            golem_api_grpc::proto::golem::rib::CallType {
352                                name:  Some(golem_api_grpc::proto::golem::rib::call_type::Name::InstanceCreation(
353                                    Box::new(golem_api_grpc::proto::golem::rib::InstanceCreationType {
354                                        kind: Some(golem_api_grpc::proto::golem::rib::instance_creation_type::Kind::Resource(Box::new(golem_api_grpc::proto::golem::rib::ResourceInstanceWithWorkerName {
355                                            component: component_info.map(golem_api_grpc::proto::golem::rib::ComponentDependencyKey::from),
356                                            worker_name: None,
357                                            resource_name: Some(golem_api_grpc::proto::golem::rib::FullyQualifiedResourceConstructor::from(resource_name)),
358                                        }))),
359                                    })
360                                )),
361                            }
362                        }
363                    }
364                }
365            }
366        }
367    }
368
369    // InvocationName is a legacy structure to keep the backward compatibility.
370    // InvocationName is corresponding to the new CallType and the difference here is,
371    // InvocationName::Function will always hold a static function name and not a dynamic one
372    // with Expr representing resource construction parameters
373    impl TryFrom<golem_api_grpc::proto::golem::rib::InvocationName> for CallType {
374        type Error = String;
375        fn try_from(
376            value: golem_api_grpc::proto::golem::rib::InvocationName,
377        ) -> Result<Self, Self::Error> {
378            let invocation = value.name.ok_or("Missing name of invocation")?;
379            match invocation {
380                golem_api_grpc::proto::golem::rib::invocation_name::Name::Parsed(name) => {
381                    Ok(CallType::Function {
382                        component_info: None,
383                        instance_identifier: None,
384                        function_name: DynamicParsedFunctionName::parse(
385                            ParsedFunctionName::try_from(name)?.to_string(),
386                        )?,
387                    })
388                }
389                golem_api_grpc::proto::golem::rib::invocation_name::Name::VariantConstructor(
390                    name,
391                ) => Ok(CallType::VariantConstructor(name)),
392                golem_api_grpc::proto::golem::rib::invocation_name::Name::EnumConstructor(name) => {
393                    Ok(CallType::EnumConstructor(name))
394                }
395            }
396        }
397    }
398}