rib/compiler/
worker_functions_in_rib.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::{ComponentDependencies, FunctionName, InferredExpr, RibCompilationError};
16use golem_wasm_ast::analysis::AnalysedType;
17
18// An easier data type that focus just on the side effecting function calls in Rib script.
19// These will not include variant or enum calls, that were originally
20// tagged as functions before compilation.
21// This is why we need a fully inferred Rib (fully compiled rib),
22// which has specific details, along with original type registry to construct this data.
23// These function calls are indeed worker invoke calls and nothing else.
24// If Rib has inbuilt function support, those will not be included here either.
25#[derive(Debug, Clone, PartialEq, Eq)]
26pub struct WorkerFunctionsInRib {
27    pub function_calls: Vec<WorkerFunctionType>,
28}
29
30impl WorkerFunctionsInRib {
31    pub fn from_inferred_expr(
32        inferred_expr: &InferredExpr,
33        component_dependency: &ComponentDependencies,
34    ) -> Result<Option<WorkerFunctionsInRib>, RibCompilationError> {
35        let worker_invoke_registry_keys = inferred_expr.worker_invoke_registry_keys();
36
37        let mut function_calls = vec![];
38
39        for key in worker_invoke_registry_keys {
40            let (_, function_type) = component_dependency
41                .get_function_type(&None, &key)
42                .map_err(|e| RibCompilationError::RibStaticAnalysisError(e.to_string()))?;
43
44            let function_call_in_rib = WorkerFunctionType {
45                function_name: key,
46                parameter_types: function_type
47                    .parameter_types
48                    .iter()
49                    .map(|param| AnalysedType::try_from(param).unwrap())
50                    .collect(),
51                return_type: function_type
52                    .return_type
53                    .as_ref()
54                    .map(|return_type| AnalysedType::try_from(return_type).unwrap()),
55            };
56
57            function_calls.push(function_call_in_rib)
58        }
59
60        if function_calls.is_empty() {
61            Ok(None)
62        } else {
63            Ok(Some(WorkerFunctionsInRib { function_calls }))
64        }
65    }
66}
67
68// The type of a function call with worker (ephmeral or durable) in Rib script
69#[derive(Debug, Clone, PartialEq, Eq)]
70pub struct WorkerFunctionType {
71    pub function_name: FunctionName,
72    pub parameter_types: Vec<AnalysedType>,
73    pub return_type: Option<AnalysedType>,
74}
75
76#[cfg(feature = "protobuf")]
77mod protobuf {
78    use crate::{FunctionName, WorkerFunctionType, WorkerFunctionsInRib};
79    use golem_api_grpc::proto::golem::rib::WorkerFunctionType as WorkerFunctionTypeProto;
80    use golem_api_grpc::proto::golem::rib::WorkerFunctionsInRib as WorkerFunctionsInRibProto;
81    use golem_wasm_ast::analysis::AnalysedType;
82
83    impl TryFrom<WorkerFunctionsInRibProto> for WorkerFunctionsInRib {
84        type Error = String;
85
86        fn try_from(value: WorkerFunctionsInRibProto) -> Result<Self, Self::Error> {
87            let function_calls_proto = value.function_calls;
88            let function_calls = function_calls_proto
89                .iter()
90                .map(|worker_function_type_proto| {
91                    WorkerFunctionType::try_from(worker_function_type_proto.clone())
92                })
93                .collect::<Result<_, _>>()?;
94            Ok(Self { function_calls })
95        }
96    }
97
98    impl From<WorkerFunctionsInRib> for WorkerFunctionsInRibProto {
99        fn from(value: WorkerFunctionsInRib) -> Self {
100            WorkerFunctionsInRibProto {
101                function_calls: value
102                    .function_calls
103                    .iter()
104                    .map(|x| WorkerFunctionTypeProto::from(x.clone()))
105                    .collect(),
106            }
107        }
108    }
109
110    impl TryFrom<WorkerFunctionTypeProto> for WorkerFunctionType {
111        type Error = String;
112
113        fn try_from(value: WorkerFunctionTypeProto) -> Result<Self, Self::Error> {
114            let return_type = value
115                .return_type
116                .as_ref()
117                .map(AnalysedType::try_from)
118                .transpose()?;
119
120            let parameter_types = value
121                .parameter_types
122                .iter()
123                .map(AnalysedType::try_from)
124                .collect::<Result<_, _>>()?;
125
126            let function_key_type = value.function_name.and_then(|x| x.function_name).ok_or(
127                "WorkerFunctionTypeProto function_key must have a function_name".to_string(),
128            )?;
129
130            let function_name = FunctionName::try_from(function_key_type)
131                .map_err(|e| format!("Failed to convert function key: {e}"))?;
132
133            Ok(Self {
134                function_name,
135                return_type,
136                parameter_types,
137            })
138        }
139    }
140
141    impl From<WorkerFunctionType> for WorkerFunctionTypeProto {
142        fn from(value: WorkerFunctionType) -> Self {
143            let function_key =
144                golem_api_grpc::proto::golem::rib::function_name_type::FunctionName::from(
145                    value.function_name,
146                );
147
148            let function_name_type = golem_api_grpc::proto::golem::rib::FunctionNameType {
149                function_name: Some(function_key),
150            };
151
152            WorkerFunctionTypeProto {
153                function_name: Some(function_name_type),
154                parameter_types: value
155                    .parameter_types
156                    .iter()
157                    .map(|analysed_type| analysed_type.into())
158                    .collect(),
159                return_type: value
160                    .return_type
161                    .as_ref()
162                    .map(|analysed_type| analysed_type.into()),
163            }
164        }
165    }
166}