golem_wasm/analysis/
protobuf.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::analysis::analysed_type::{
16    bool, chr, f32, f64, field, flags, handle, list, option, r#enum, record, s16, s32, s64, s8,
17    str, tuple, u16, u32, u64, u8, variant,
18};
19use crate::analysis::{AnalysedResourceId, AnalysedResourceMode, AnalysedType};
20use crate::protobuf::{
21    r#type, NameOptionTypePair, NameTypePair, PrimitiveType, Type, TypeEnum, TypeFlags, TypeHandle,
22    TypeList, TypeOption, TypePrimitive, TypeRecord, TypeResult, TypeTuple, TypeVariant,
23};
24use std::ops::Deref;
25
26impl TryFrom<&Type> for AnalysedType {
27    type Error = String;
28
29    fn try_from(typ: &Type) -> Result<Self, Self::Error> {
30        match &typ.r#type {
31            Some(r#type::Type::Primitive(primitive)) => {
32                match PrimitiveType::try_from(primitive.primitive) {
33                    Ok(PrimitiveType::Bool) => Ok(bool()),
34                    Ok(PrimitiveType::S8) => Ok(s8()),
35                    Ok(PrimitiveType::U8) => Ok(u8()),
36                    Ok(PrimitiveType::S16) => Ok(s16()),
37                    Ok(PrimitiveType::U16) => Ok(u16()),
38                    Ok(PrimitiveType::S32) => Ok(s32()),
39                    Ok(PrimitiveType::U32) => Ok(u32()),
40                    Ok(PrimitiveType::S64) => Ok(s64()),
41                    Ok(PrimitiveType::U64) => Ok(u64()),
42                    Ok(PrimitiveType::F32) => Ok(f32()),
43                    Ok(PrimitiveType::F64) => Ok(f64()),
44                    Ok(PrimitiveType::Chr) => Ok(chr()),
45                    Ok(PrimitiveType::Str) => Ok(str()),
46                    Err(_) => Err("Unknown primitive type".to_string()),
47                }
48            }
49            Some(r#type::Type::List(inner)) => {
50                let elem_type = inner
51                    .elem
52                    .as_ref()
53                    .ok_or_else(|| "List element type is None".to_string())?;
54                let analysed_type = AnalysedType::try_from(elem_type.as_ref())?;
55                Ok(list(analysed_type)
56                    .with_optional_name(inner.name.clone())
57                    .with_optional_owner(inner.owner.clone()))
58            }
59            Some(r#type::Type::Tuple(inner)) => {
60                let elems = inner
61                    .elems
62                    .iter()
63                    .map(AnalysedType::try_from)
64                    .collect::<Result<Vec<_>, String>>()?;
65                Ok(tuple(elems)
66                    .with_optional_name(inner.name.clone())
67                    .with_optional_owner(inner.owner.clone()))
68            }
69            Some(r#type::Type::Record(inner)) => {
70                let fields = inner
71                    .fields
72                    .iter()
73                    .map(|proto_field| {
74                        let field_type = proto_field.typ.as_ref().ok_or_else(|| {
75                            format!("Record field {} type is None", proto_field.name)
76                        })?;
77                        let analysed_type = AnalysedType::try_from(field_type)?;
78                        Ok(field(&proto_field.name, analysed_type))
79                    })
80                    .collect::<Result<Vec<_>, String>>()?;
81                Ok(record(fields)
82                    .with_optional_name(inner.name.clone())
83                    .with_optional_owner(inner.owner.clone()))
84            }
85            Some(r#type::Type::Flags(inner)) => Ok(flags(
86                &inner
87                    .names
88                    .iter()
89                    .map(|s| s.as_str())
90                    .collect::<Vec<&str>>(),
91            )
92            .with_optional_name(inner.name.clone())
93            .with_optional_owner(inner.owner.clone())),
94            Some(r#type::Type::Enum(inner)) => Ok(r#enum(
95                &inner
96                    .names
97                    .iter()
98                    .map(|s| s.as_str())
99                    .collect::<Vec<&str>>(),
100            )
101            .with_optional_name(inner.name.clone())
102            .with_optional_owner(inner.owner.clone())),
103            Some(r#type::Type::Option(inner)) => {
104                let elem_type = inner
105                    .elem
106                    .as_ref()
107                    .ok_or_else(|| "Option element type is None".to_string())?;
108                let analysed_type = AnalysedType::try_from(elem_type.as_ref())?;
109                Ok(option(analysed_type)
110                    .with_optional_name(inner.name.clone())
111                    .with_optional_owner(inner.owner.clone()))
112            }
113            Some(r#type::Type::Result(inner)) => {
114                let ok_type = inner
115                    .ok
116                    .as_ref()
117                    .map(|tpe| AnalysedType::try_from(tpe.as_ref()))
118                    .transpose()?;
119                let err_type = inner
120                    .err
121                    .as_ref()
122                    .map(|tpe| AnalysedType::try_from(tpe.as_ref()))
123                    .transpose()?;
124                Ok(AnalysedType::Result(crate::analysis::TypeResult {
125                    ok: ok_type.map(Box::new),
126                    err: err_type.map(Box::new),
127                    name: inner.name.clone(),
128                    owner: inner.owner.clone(),
129                })
130                .with_optional_name(inner.name.clone())
131                .with_optional_owner(inner.owner.clone()))
132            }
133            Some(r#type::Type::Variant(inner)) => {
134                let cases = inner
135                    .cases
136                    .iter()
137                    .map(|case| {
138                        let case_type =
139                            case.typ.as_ref().map(AnalysedType::try_from).transpose()?;
140                        Ok(crate::analysis::NameOptionTypePair {
141                            name: case.name.clone(),
142                            typ: case_type,
143                        })
144                    })
145                    .collect::<Result<Vec<_>, String>>()?;
146                Ok(variant(cases)
147                    .with_optional_name(inner.name.clone())
148                    .with_optional_owner(inner.owner.clone()))
149            }
150            Some(r#type::Type::Handle(inner)) => {
151                let resource_mode = match inner.mode {
152                    0 => Ok(AnalysedResourceMode::Owned),
153                    1 => Ok(AnalysedResourceMode::Borrowed),
154                    _ => Err("Invalid resource mode".to_string()),
155                }?;
156                Ok(handle(AnalysedResourceId(inner.resource_id), resource_mode)
157                    .with_optional_name(inner.name.clone())
158                    .with_optional_owner(inner.owner.clone()))
159            }
160            None => Err("Type is None".to_string()),
161        }
162    }
163}
164
165impl From<&AnalysedType> for Type {
166    fn from(value: &AnalysedType) -> Type {
167        let r#type = match value {
168            AnalysedType::Bool(_) => Some(r#type::Type::Primitive(TypePrimitive {
169                primitive: PrimitiveType::Bool as i32,
170            })),
171            AnalysedType::S8(_) => Some(r#type::Type::Primitive(TypePrimitive {
172                primitive: PrimitiveType::S8 as i32,
173            })),
174            AnalysedType::U8(_) => Some(r#type::Type::Primitive(TypePrimitive {
175                primitive: PrimitiveType::U8 as i32,
176            })),
177            AnalysedType::S16(_) => Some(r#type::Type::Primitive(TypePrimitive {
178                primitive: PrimitiveType::S16 as i32,
179            })),
180            AnalysedType::U16(_) => Some(r#type::Type::Primitive(TypePrimitive {
181                primitive: PrimitiveType::U16 as i32,
182            })),
183            AnalysedType::S32(_) => Some(r#type::Type::Primitive(TypePrimitive {
184                primitive: PrimitiveType::S32 as i32,
185            })),
186            AnalysedType::U32(_) => Some(r#type::Type::Primitive(TypePrimitive {
187                primitive: PrimitiveType::U32 as i32,
188            })),
189            AnalysedType::S64(_) => Some(r#type::Type::Primitive(TypePrimitive {
190                primitive: PrimitiveType::S64 as i32,
191            })),
192            AnalysedType::U64(_) => Some(r#type::Type::Primitive(TypePrimitive {
193                primitive: PrimitiveType::U64 as i32,
194            })),
195            AnalysedType::F32(_) => Some(r#type::Type::Primitive(TypePrimitive {
196                primitive: PrimitiveType::F32 as i32,
197            })),
198            AnalysedType::F64(_) => Some(r#type::Type::Primitive(TypePrimitive {
199                primitive: PrimitiveType::F64 as i32,
200            })),
201            AnalysedType::Chr(_) => Some(r#type::Type::Primitive(TypePrimitive {
202                primitive: PrimitiveType::Chr as i32,
203            })),
204            AnalysedType::Str(_) => Some(r#type::Type::Primitive(TypePrimitive {
205                primitive: PrimitiveType::Str as i32,
206            })),
207            AnalysedType::List(crate::analysis::TypeList { inner, name, owner }) => {
208                Some(r#type::Type::List(Box::new(TypeList {
209                    elem: Some(Box::new(Type::from(inner.deref()))),
210                    name: name.clone(),
211                    owner: owner.clone(),
212                })))
213            }
214            AnalysedType::Tuple(crate::analysis::TypeTuple { items, name, owner }) => {
215                Some(r#type::Type::Tuple(TypeTuple {
216                    elems: items
217                        .iter()
218                        .map(|analysed_type| analysed_type.into())
219                        .collect(),
220                    name: name.clone(),
221                    owner: owner.clone(),
222                }))
223            }
224            AnalysedType::Record(crate::analysis::TypeRecord {
225                fields,
226                name,
227                owner,
228            }) => Some(r#type::Type::Record(TypeRecord {
229                fields: fields
230                    .iter()
231                    .map(|pair| NameTypePair {
232                        name: pair.name.clone(),
233                        typ: Some((&pair.typ).into()),
234                    })
235                    .collect(),
236                name: name.clone(),
237                owner: owner.clone(),
238            })),
239            AnalysedType::Flags(crate::analysis::TypeFlags { names, name, owner }) => {
240                Some(r#type::Type::Flags(TypeFlags {
241                    names: names.clone(),
242                    name: name.clone(),
243                    owner: owner.clone(),
244                }))
245            }
246            AnalysedType::Enum(crate::analysis::TypeEnum { cases, name, owner }) => {
247                Some(r#type::Type::Enum(TypeEnum {
248                    names: cases.clone(),
249                    name: name.clone(),
250                    owner: owner.clone(),
251                }))
252            }
253            AnalysedType::Option(crate::analysis::TypeOption { inner, name, owner }) => {
254                Some(r#type::Type::Option(Box::new(TypeOption {
255                    elem: Some(Box::new(Type::from(inner.deref()))),
256                    name: name.clone(),
257                    owner: owner.clone(),
258                })))
259            }
260            AnalysedType::Result(crate::analysis::TypeResult {
261                ok,
262                err,
263                name,
264                owner,
265            }) => Some(r#type::Type::Result(Box::new(TypeResult {
266                ok: ok
267                    .clone()
268                    .map(|ok_type| Box::new(Type::from(ok_type.as_ref()))),
269                err: err
270                    .clone()
271                    .map(|err_type| Box::new(Type::from(err_type.as_ref()))),
272                name: name.clone(),
273                owner: owner.clone(),
274            }))),
275            AnalysedType::Variant(crate::analysis::TypeVariant { cases, name, owner }) => {
276                Some(r#type::Type::Variant(TypeVariant {
277                    cases: cases
278                        .iter()
279                        .map(|pair| NameOptionTypePair {
280                            name: pair.name.clone(),
281                            typ: pair.typ.as_ref().map(|analysed_type| analysed_type.into()),
282                        })
283                        .collect(),
284                    name: name.clone(),
285                    owner: owner.clone(),
286                }))
287            }
288            AnalysedType::Handle(crate::analysis::TypeHandle {
289                resource_id,
290                mode,
291                name,
292                owner,
293            }) => Some(r#type::Type::Handle(TypeHandle {
294                resource_id: resource_id.0,
295                mode: match mode {
296                    AnalysedResourceMode::Owned => 0,
297                    AnalysedResourceMode::Borrowed => 1,
298                },
299                name: name.clone(),
300                owner: owner.clone(),
301            })),
302        };
303
304        Type { r#type }
305    }
306}