rib/
call_type.rs

1// Copyright 2024-2025 Golem Cloud
2//
3// Licensed under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0
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::instance_type::FullyQualifiedResourceConstructor;
16use crate::{DynamicParsedFunctionName, Expr};
17use std::fmt::Display;
18use std::ops::Deref;
19
20#[derive(Debug, Hash, PartialEq, Eq, Clone, Ord, PartialOrd)]
21pub enum CallType {
22    Function {
23        worker: Option<Box<Expr>>,
24        function_name: DynamicParsedFunctionName,
25    },
26    VariantConstructor(String),
27    EnumConstructor(String),
28    InstanceCreation(InstanceCreationType),
29}
30
31#[derive(Debug, Hash, PartialEq, Eq, Clone, Ord, PartialOrd)]
32pub enum InstanceCreationType {
33    Worker {
34        worker_name: Option<Box<Expr>>,
35    },
36    Resource {
37        worker_name: Option<Box<Expr>>,
38        resource_name: FullyQualifiedResourceConstructor,
39    },
40}
41
42impl InstanceCreationType {
43    pub fn worker_name(&self) -> Option<Expr> {
44        match self {
45            InstanceCreationType::Worker { worker_name, .. } => {
46                worker_name.clone().map(|w| w.deref().clone())
47            }
48            InstanceCreationType::Resource { worker_name, .. } => {
49                worker_name.clone().map(|w| w.deref().clone())
50            }
51        }
52    }
53}
54
55impl CallType {
56    pub fn function_name(&self) -> Option<DynamicParsedFunctionName> {
57        match self {
58            CallType::Function { function_name, .. } => Some(function_name.clone()),
59            _ => None,
60        }
61    }
62    pub fn worker_expr(&self) -> Option<&Expr> {
63        match self {
64            CallType::Function { worker, .. } => worker.as_deref(),
65            _ => None,
66        }
67    }
68
69    pub fn worker_expr_mut(&mut self) -> Option<&mut Box<Expr>> {
70        match self {
71            CallType::Function { worker, .. } => worker.as_mut(),
72            _ => None,
73        }
74    }
75    pub fn function_without_worker(function: DynamicParsedFunctionName) -> CallType {
76        CallType::Function {
77            worker: None,
78            function_name: function,
79        }
80    }
81    pub fn is_resource_method(&self) -> bool {
82        match self {
83            CallType::Function { function_name, .. } => function_name
84                .to_parsed_function_name()
85                .function
86                .resource_method_name()
87                .is_some(),
88            _ => false,
89        }
90    }
91}
92
93impl Display for CallType {
94    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95        match self {
96            CallType::Function { function_name, .. } => write!(f, "{}", function_name),
97            CallType::VariantConstructor(name) => write!(f, "{}", name),
98            CallType::EnumConstructor(name) => write!(f, "{}", name),
99            CallType::InstanceCreation(instance_creation_type) => match instance_creation_type {
100                InstanceCreationType::Worker { .. } => {
101                    write!(f, "instance")
102                }
103                InstanceCreationType::Resource { resource_name, .. } => {
104                    write!(f, "{}", resource_name.resource_name)
105                }
106            },
107        }
108    }
109}
110
111#[cfg(feature = "protobuf")]
112mod protobuf {
113    use crate::call_type::{CallType, InstanceCreationType};
114    use crate::instance_type::FullyQualifiedResourceConstructor;
115    use crate::{DynamicParsedFunctionName, Expr, ParsedFunctionName};
116    use golem_api_grpc::proto::golem::rib::WorkerInstance;
117
118    impl TryFrom<golem_api_grpc::proto::golem::rib::InstanceCreationType> for InstanceCreationType {
119        type Error = String;
120        fn try_from(
121            value: golem_api_grpc::proto::golem::rib::InstanceCreationType,
122        ) -> Result<Self, Self::Error> {
123            match value.kind.ok_or("Missing instance creation kind")? {
124                golem_api_grpc::proto::golem::rib::instance_creation_type::Kind::Worker(
125                    worker_instance,
126                ) => {
127                    let worker_name = worker_instance
128                        .worker_name
129                        .map(|w| Expr::try_from(*w))
130                        .transpose()?
131                        .map(Box::new);
132
133                    Ok(InstanceCreationType::Worker { worker_name })
134                }
135                golem_api_grpc::proto::golem::rib::instance_creation_type::Kind::Resource(
136                    resource_instance,
137                ) => {
138                    let worker_name = resource_instance
139                        .worker_name
140                        .map(|w| Expr::try_from(*w))
141                        .transpose()?
142                        .map(Box::new);
143                    let resource_constructor_proto = resource_instance
144                        .resource_name
145                        .ok_or("Missing resource name")?;
146                    let resource_name =
147                        FullyQualifiedResourceConstructor::try_from(resource_constructor_proto)?;
148
149                    Ok(InstanceCreationType::Resource {
150                        worker_name,
151                        resource_name,
152                    })
153                }
154            }
155        }
156    }
157
158    impl From<InstanceCreationType> for golem_api_grpc::proto::golem::rib::InstanceCreationType {
159        fn from(value: InstanceCreationType) -> Self {
160            match value {
161                InstanceCreationType::Worker { worker_name } => {
162                    golem_api_grpc::proto::golem::rib::InstanceCreationType {
163                        kind: Some(golem_api_grpc::proto::golem::rib::instance_creation_type::Kind::Worker(Box::new(WorkerInstance {
164                            worker_name: worker_name.clone().map(|w| Box::new(golem_api_grpc::proto::golem::rib::Expr::from(*w))),
165                        }))),
166                    }
167                }
168                InstanceCreationType::Resource { worker_name, resource_name } => {
169                    golem_api_grpc::proto::golem::rib::InstanceCreationType {
170                        kind: Some(golem_api_grpc::proto::golem::rib::instance_creation_type::Kind::Resource(Box::new(golem_api_grpc::proto::golem::rib::ResourceInstanceWithWorkerName {
171                            worker_name: worker_name.clone().map(|w| Box::new(golem_api_grpc::proto::golem::rib::Expr::from(*w))),
172                            resource_name: Some(golem_api_grpc::proto::golem::rib::FullyQualifiedResourceConstructor::from(resource_name)),
173                        }))),
174                    }
175                }
176            }
177        }
178    }
179
180    impl TryFrom<golem_api_grpc::proto::golem::rib::CallType> for CallType {
181        type Error = String;
182        fn try_from(
183            value: golem_api_grpc::proto::golem::rib::CallType,
184        ) -> Result<Self, Self::Error> {
185            let invocation = value.name.ok_or("Missing name of invocation")?;
186            let worker = value
187                .worker_name
188                .map(|w| Expr::try_from(*w))
189                .transpose()?
190                .map(Box::new);
191            match invocation {
192                golem_api_grpc::proto::golem::rib::call_type::Name::Parsed(name) => {
193                    Ok(CallType::Function {
194                        function_name: DynamicParsedFunctionName::try_from(name)?,
195                        worker,
196                    })
197                }
198                golem_api_grpc::proto::golem::rib::call_type::Name::VariantConstructor(name) => {
199                    Ok(CallType::VariantConstructor(name))
200                }
201                golem_api_grpc::proto::golem::rib::call_type::Name::EnumConstructor(name) => {
202                    Ok(CallType::EnumConstructor(name))
203                }
204
205                golem_api_grpc::proto::golem::rib::call_type::Name::InstanceCreation(
206                    instance_creation,
207                ) => {
208                    let instance_creation = InstanceCreationType::try_from(*instance_creation)?;
209                    Ok(CallType::InstanceCreation(instance_creation))
210                }
211            }
212        }
213    }
214
215    impl From<CallType> for golem_api_grpc::proto::golem::rib::CallType {
216        fn from(value: CallType) -> Self {
217            match value {
218                CallType::Function {
219                    worker,
220                    function_name,
221                } => golem_api_grpc::proto::golem::rib::CallType {
222                    worker_name: worker.map(|w| Box::new(golem_api_grpc::proto::golem::rib::Expr::from(*w))),
223                    name: Some(golem_api_grpc::proto::golem::rib::call_type::Name::Parsed(
224                        function_name.into(),
225                    )),
226                },
227                CallType::VariantConstructor(name) => golem_api_grpc::proto::golem::rib::CallType {
228                    worker_name: None,
229                    name: Some(
230                        golem_api_grpc::proto::golem::rib::call_type::Name::VariantConstructor(
231                            name,
232                        ),
233                    ),
234                },
235                CallType::EnumConstructor(name) => golem_api_grpc::proto::golem::rib::CallType {
236                    worker_name: None,
237                    name: Some(
238                        golem_api_grpc::proto::golem::rib::call_type::Name::EnumConstructor(name),
239                    ),
240                },
241                CallType::InstanceCreation(instance_creation) => {
242                    match instance_creation {
243                        InstanceCreationType::Worker { worker_name } => {
244                            golem_api_grpc::proto::golem::rib::CallType {
245                                worker_name: worker_name.clone().map(|w| Box::new(golem_api_grpc::proto::golem::rib::Expr::from(*w))),
246                                name:  Some(golem_api_grpc::proto::golem::rib::call_type::Name::InstanceCreation(
247                                    Box::new(golem_api_grpc::proto::golem::rib::InstanceCreationType {
248                                        kind: Some(golem_api_grpc::proto::golem::rib::instance_creation_type::Kind::Worker(Box::new(WorkerInstance {
249                                            worker_name: worker_name.map(|w| Box::new(golem_api_grpc::proto::golem::rib::Expr::from(*w))),
250                                        }))),
251                                    })
252                                )),
253                            }
254                        }
255                        InstanceCreationType::Resource { worker_name, resource_name } => {
256                            golem_api_grpc::proto::golem::rib::CallType {
257                                worker_name: worker_name.clone().map(|w| Box::new(golem_api_grpc::proto::golem::rib::Expr::from(*w))),
258                                name:  Some(golem_api_grpc::proto::golem::rib::call_type::Name::InstanceCreation(
259                                    Box::new(golem_api_grpc::proto::golem::rib::InstanceCreationType {
260                                        kind: Some(golem_api_grpc::proto::golem::rib::instance_creation_type::Kind::Resource(Box::new(golem_api_grpc::proto::golem::rib::ResourceInstanceWithWorkerName {
261                                            worker_name: worker_name.map(|w| Box::new(golem_api_grpc::proto::golem::rib::Expr::from(*w))),
262                                            resource_name: Some(golem_api_grpc::proto::golem::rib::FullyQualifiedResourceConstructor::from(resource_name)),
263                                        }))),
264                                    })
265                                )),
266                            }
267                        }
268                    }
269                }
270            }
271        }
272    }
273
274    // InvocationName is a legacy structure to keep the backward compatibility.
275    // InvocationName is corresponding to the new CallType and the difference here is,
276    // InvocationName::Function will always hold a static function name and not a dynamic one
277    // with Expr representing resource construction parameters
278    impl TryFrom<golem_api_grpc::proto::golem::rib::InvocationName> for CallType {
279        type Error = String;
280        fn try_from(
281            value: golem_api_grpc::proto::golem::rib::InvocationName,
282        ) -> Result<Self, Self::Error> {
283            let invocation = value.name.ok_or("Missing name of invocation")?;
284            match invocation {
285                golem_api_grpc::proto::golem::rib::invocation_name::Name::Parsed(name) => {
286                    Ok(CallType::Function {
287                        worker: None,
288                        function_name: DynamicParsedFunctionName::parse(
289                            ParsedFunctionName::try_from(name)?.to_string(),
290                        )?,
291                    })
292                }
293                golem_api_grpc::proto::golem::rib::invocation_name::Name::VariantConstructor(
294                    name,
295                ) => Ok(CallType::VariantConstructor(name)),
296                golem_api_grpc::proto::golem::rib::invocation_name::Name::EnumConstructor(name) => {
297                    Ok(CallType::EnumConstructor(name))
298                }
299            }
300        }
301    }
302}