rib/compiler/
type_with_unit.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::InferredType;
16use bincode::{Decode, Encode};
17use golem_wasm_ast::analysis::analysed_type::{bool, field, option, record, tuple};
18use golem_wasm_ast::analysis::{
19    AnalysedResourceId, AnalysedResourceMode, AnalysedType, NameOptionTypePair, NameTypePair,
20    TypeBool, TypeChr, TypeEnum, TypeF32, TypeF64, TypeFlags, TypeHandle, TypeList, TypeOption,
21    TypeRecord, TypeResult, TypeS16, TypeS32, TypeS64, TypeS8, TypeStr, TypeTuple, TypeU16,
22    TypeU32, TypeU64, TypeU8, TypeVariant,
23};
24use serde::{Deserialize, Serialize};
25
26#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode)]
27pub enum AnalysedTypeWithUnit {
28    Unit,
29    Type(AnalysedType),
30}
31
32impl AnalysedTypeWithUnit {
33    pub fn unit() -> Self {
34        AnalysedTypeWithUnit::Unit
35    }
36
37    pub fn analysed_type(typ: AnalysedType) -> Self {
38        AnalysedTypeWithUnit::Type(typ)
39    }
40}
41
42impl TryFrom<AnalysedTypeWithUnit> for AnalysedType {
43    type Error = String;
44
45    fn try_from(value: AnalysedTypeWithUnit) -> Result<Self, Self::Error> {
46        match value {
47            AnalysedTypeWithUnit::Unit => Ok(tuple(vec![])),
48            AnalysedTypeWithUnit::Type(typ) => Ok(typ),
49        }
50    }
51}
52
53impl TryFrom<&InferredType> for AnalysedType {
54    type Error = String;
55
56    fn try_from(value: &InferredType) -> Result<Self, Self::Error> {
57        let with_unit = AnalysedTypeWithUnit::try_from(value)?;
58        AnalysedType::try_from(with_unit)
59    }
60}
61
62impl TryFrom<&InferredType> for AnalysedTypeWithUnit {
63    type Error = String;
64
65    fn try_from(inferred_type: &InferredType) -> Result<Self, Self::Error> {
66        match inferred_type {
67            InferredType::Instance { .. } => {
68                Err("Cannot convert Instance type to AnalysedType".to_string())
69            }
70            InferredType::Range { from, to } => {
71                let from: AnalysedType = AnalysedType::try_from(from.as_ref())?;
72                let to: Option<AnalysedType> = to
73                    .as_ref()
74                    .map(|t| AnalysedType::try_from(t.as_ref()))
75                    .transpose()?;
76                let analysed_type = match (from, to) {
77                    (from_type, Some(to_type)) => record(vec![
78                        field("from", option(from_type)),
79                        field("to", option(to_type)),
80                        field("inclusive", bool()),
81                    ]),
82
83                    (from_type, None) => record(vec![
84                        field("from", option(from_type)),
85                        field("inclusive", bool()),
86                    ]),
87                };
88                Ok(AnalysedTypeWithUnit::analysed_type(analysed_type))
89            }
90            InferredType::Bool => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::Bool(
91                TypeBool,
92            ))),
93            InferredType::S8 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::S8(
94                TypeS8,
95            ))),
96            InferredType::U8 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::U8(
97                TypeU8,
98            ))),
99            InferredType::S16 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::S16(
100                TypeS16,
101            ))),
102            InferredType::U16 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::U16(
103                TypeU16,
104            ))),
105            InferredType::S32 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::S32(
106                TypeS32,
107            ))),
108            InferredType::U32 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::U32(
109                TypeU32,
110            ))),
111            InferredType::S64 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::S64(
112                TypeS64,
113            ))),
114            InferredType::U64 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::U64(
115                TypeU64,
116            ))),
117            InferredType::F32 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::F32(
118                TypeF32,
119            ))),
120            InferredType::F64 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::F64(
121                TypeF64,
122            ))),
123            InferredType::Chr => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::Chr(
124                TypeChr,
125            ))),
126            InferredType::Str => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::Str(
127                TypeStr,
128            ))),
129            InferredType::List(inferred_type) => Ok(AnalysedTypeWithUnit::analysed_type(
130                AnalysedType::List(TypeList {
131                    inner: Box::new(inferred_type.as_ref().try_into()?),
132                }),
133            )),
134            InferredType::Tuple(tuple) => Ok(AnalysedTypeWithUnit::analysed_type(
135                AnalysedType::Tuple(TypeTuple {
136                    items: tuple
137                        .iter()
138                        .map(|t| t.try_into())
139                        .collect::<Result<Vec<AnalysedType>, String>>()?,
140                }),
141            )),
142            InferredType::Record(record) => Ok(AnalysedTypeWithUnit::analysed_type(
143                AnalysedType::Record(TypeRecord {
144                    fields: record
145                        .iter()
146                        .map(|(name, typ)| {
147                            Ok(NameTypePair {
148                                name: name.to_string(),
149                                typ: typ.try_into()?,
150                            })
151                        })
152                        .collect::<Result<Vec<NameTypePair>, String>>()?,
153                }),
154            )),
155            InferredType::Flags(flags) => Ok(AnalysedTypeWithUnit::analysed_type(
156                AnalysedType::Flags(TypeFlags {
157                    names: flags.clone(),
158                }),
159            )),
160            InferredType::Enum(enums) => Ok(AnalysedTypeWithUnit::analysed_type(
161                AnalysedType::Enum(TypeEnum {
162                    cases: enums.clone(),
163                }),
164            )),
165            InferredType::Option(option) => Ok(AnalysedTypeWithUnit::analysed_type(
166                AnalysedType::Option(TypeOption {
167                    inner: Box::new(option.as_ref().try_into()?),
168                }),
169            )),
170            InferredType::Result { ok, error } => Ok(AnalysedTypeWithUnit::analysed_type(
171                // In the case of result, there are instances users give just 1 value with zero function calls, we need to be flexible here
172                AnalysedType::Result(TypeResult {
173                    ok: ok
174                        .as_ref()
175                        .and_then(|t| t.as_ref().try_into().ok().map(Box::new)),
176                    err: error
177                        .as_ref()
178                        .and_then(|t| t.as_ref().try_into().ok().map(Box::new)),
179                }),
180            )),
181            InferredType::Variant(variant) => Ok(AnalysedTypeWithUnit::analysed_type(
182                AnalysedType::Variant(TypeVariant {
183                    cases: variant
184                        .iter()
185                        .map(|(name, typ)| {
186                            Ok(NameOptionTypePair {
187                                name: name.clone(),
188                                typ: typ.as_ref().map(|t| t.try_into()).transpose()?,
189                            })
190                        })
191                        .collect::<Result<Vec<NameOptionTypePair>, String>>()?,
192                }),
193            )),
194            InferredType::Resource {
195                resource_id,
196                resource_mode,
197            } => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::Handle(
198                TypeHandle {
199                    resource_id: AnalysedResourceId(*resource_id),
200                    mode: if resource_mode == &0 {
201                        AnalysedResourceMode::Owned
202                    } else {
203                        AnalysedResourceMode::Borrowed
204                    },
205                },
206            ))),
207
208            InferredType::OneOf(_) => Err(
209                "Cannot convert OneOf types (different possibilities of types) to AnalysedType"
210                    .to_string(),
211            ),
212            InferredType::AllOf(types) => Err(format!(
213                "Cannot convert AllOf types (multiple types) to AnalysedType. {:?}",
214                types
215            )),
216            InferredType::Unknown => Err("  convert Unknown type to AnalysedType".to_string()),
217            // We don't expect to have a sequence type in the inferred type.as
218            // This implies Rib will not support multiple types from worker-function results
219            InferredType::Sequence(vec) => {
220                if vec.is_empty() {
221                    Ok(AnalysedTypeWithUnit::unit())
222                } else if vec.len() == 1 {
223                    let first = &vec[0];
224                    Ok(first.try_into()?)
225                } else {
226                    Err("Cannot convert Sequence type to AnalysedType".to_string())
227                }
228            }
229        }
230    }
231}