golem_wasm/
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::{AnalysedFunctionParameter, AnalysedType};
16use crate::Value;
17
18include!(concat!(env!("OUT_DIR"), "/wasm.rpc.rs"));
19
20// Conversion from WIT WitValue to Protobuf WitValue
21
22impl From<super::WitValue> for WitValue {
23    fn from(value: super::WitValue) -> Self {
24        WitValue {
25            nodes: value.nodes.into_iter().map(|node| node.into()).collect(),
26        }
27    }
28}
29
30impl From<super::WitNode> for WitNode {
31    fn from(value: super::WitNode) -> Self {
32        match value {
33            super::WitNode::RecordValue(fields) => WitNode {
34                value: Some(wit_node::Value::Record(WitRecordNode { fields })),
35            },
36            super::WitNode::VariantValue((case_index, case_value)) => WitNode {
37                value: Some(wit_node::Value::Variant(WitVariantNode {
38                    case_index,
39                    case_value,
40                })),
41            },
42            super::WitNode::EnumValue(value) => WitNode {
43                value: Some(wit_node::Value::Enum(WitEnumNode { value })),
44            },
45            super::WitNode::FlagsValue(flags) => WitNode {
46                value: Some(wit_node::Value::Flags(WitFlagsNode { flags })),
47            },
48            super::WitNode::TupleValue(values) => WitNode {
49                value: Some(wit_node::Value::Tuple(WitTupleNode { values })),
50            },
51            super::WitNode::ListValue(values) => WitNode {
52                value: Some(wit_node::Value::List(WitListNode { values })),
53            },
54            super::WitNode::OptionValue(value) => WitNode {
55                value: Some(wit_node::Value::Option(WitOptionNode { value })),
56            },
57            super::WitNode::ResultValue(type_idx) => WitNode {
58                value: Some(wit_node::Value::Result(WitResultNode {
59                    discriminant: if type_idx.is_ok() { 0 } else { 1 },
60                    value: type_idx.unwrap_or_else(|index| index),
61                })),
62            },
63            super::WitNode::PrimU8(value) => WitNode {
64                value: Some(wit_node::Value::U8(WitPrimU8Node {
65                    value: value as u32,
66                })),
67            },
68            super::WitNode::PrimU16(value) => WitNode {
69                value: Some(wit_node::Value::U16(WitPrimU16Node {
70                    value: value as u32,
71                })),
72            },
73            super::WitNode::PrimU32(value) => WitNode {
74                value: Some(wit_node::Value::U32(WitPrimU32Node { value })),
75            },
76            super::WitNode::PrimU64(value) => WitNode {
77                value: Some(wit_node::Value::U64(WitPrimU64Node { value })),
78            },
79            super::WitNode::PrimS8(value) => WitNode {
80                value: Some(wit_node::Value::I8(WitPrimI8Node {
81                    value: value as i32,
82                })),
83            },
84            super::WitNode::PrimS16(value) => WitNode {
85                value: Some(wit_node::Value::I16(WitPrimI16Node {
86                    value: value as i32,
87                })),
88            },
89            super::WitNode::PrimS32(value) => WitNode {
90                value: Some(wit_node::Value::I32(WitPrimI32Node { value })),
91            },
92            super::WitNode::PrimS64(value) => WitNode {
93                value: Some(wit_node::Value::I64(WitPrimI64Node { value })),
94            },
95            super::WitNode::PrimFloat32(value) => WitNode {
96                value: Some(wit_node::Value::F32(WitPrimF32Node { value })),
97            },
98            super::WitNode::PrimFloat64(value) => WitNode {
99                value: Some(wit_node::Value::F64(WitPrimF64Node { value })),
100            },
101            super::WitNode::PrimChar(value) => WitNode {
102                value: Some(wit_node::Value::Char(WitPrimCharNode {
103                    value: value as u32,
104                })),
105            },
106            super::WitNode::PrimBool(value) => WitNode {
107                value: Some(wit_node::Value::Bool(WitPrimBoolNode { value })),
108            },
109            super::WitNode::PrimString(value) => WitNode {
110                value: Some(wit_node::Value::String(WitPrimStringNode { value })),
111            },
112            super::WitNode::Handle((uri, value)) => WitNode {
113                value: Some(wit_node::Value::Handle(WitHandleNode {
114                    uri: uri.value,
115                    value,
116                })),
117            },
118        }
119    }
120}
121
122// Conversion from Protobuf WitValue to WIT WitValue
123impl TryFrom<WitValue> for super::WitValue {
124    type Error = String;
125
126    fn try_from(value: WitValue) -> Result<Self, Self::Error> {
127        Ok(super::WitValue {
128            nodes: value
129                .nodes
130                .into_iter()
131                .map(|node| node.try_into())
132                .collect::<Result<Vec<_>, _>>()?,
133        })
134    }
135}
136
137impl TryFrom<WitNode> for super::WitNode {
138    type Error = String;
139
140    fn try_from(value: WitNode) -> Result<Self, Self::Error> {
141        match value.value {
142            None => Err("Protobuf WitNode has no value".to_string()),
143            Some(wit_node::Value::Record(WitRecordNode { fields })) => {
144                Ok(super::WitNode::RecordValue(fields))
145            }
146            Some(wit_node::Value::Variant(WitVariantNode {
147                case_index,
148                case_value,
149            })) => Ok(super::WitNode::VariantValue((case_index, case_value))),
150            Some(wit_node::Value::Enum(WitEnumNode { value })) => {
151                Ok(super::WitNode::EnumValue(value))
152            }
153            Some(wit_node::Value::Flags(WitFlagsNode { flags })) => {
154                Ok(super::WitNode::FlagsValue(flags))
155            }
156            Some(wit_node::Value::Tuple(WitTupleNode { values })) => {
157                Ok(super::WitNode::TupleValue(values))
158            }
159            Some(wit_node::Value::List(WitListNode { values })) => {
160                Ok(super::WitNode::ListValue(values))
161            }
162            Some(wit_node::Value::Option(WitOptionNode { value })) => {
163                Ok(super::WitNode::OptionValue(value))
164            }
165            Some(wit_node::Value::Result(WitResultNode {
166                discriminant,
167                value,
168            })) => match discriminant {
169                0 => Ok(super::WitNode::ResultValue(Ok(value))),
170                1 => Ok(super::WitNode::ResultValue(Err(value))),
171                _ => Err("Protobuf WitResultNode has invalid discriminant".to_string()),
172            },
173            Some(wit_node::Value::U8(WitPrimU8Node { value })) => {
174                Ok(super::WitNode::PrimU8(value as u8))
175            }
176            Some(wit_node::Value::U16(WitPrimU16Node { value })) => {
177                Ok(super::WitNode::PrimU16(value as u16))
178            }
179            Some(wit_node::Value::U32(WitPrimU32Node { value })) => {
180                Ok(super::WitNode::PrimU32(value))
181            }
182            Some(wit_node::Value::U64(WitPrimU64Node { value })) => {
183                Ok(super::WitNode::PrimU64(value))
184            }
185            Some(wit_node::Value::I8(WitPrimI8Node { value })) => {
186                Ok(super::WitNode::PrimS8(value as i8))
187            }
188            Some(wit_node::Value::I16(WitPrimI16Node { value })) => {
189                Ok(super::WitNode::PrimS16(value as i16))
190            }
191            Some(wit_node::Value::I32(WitPrimI32Node { value })) => {
192                Ok(super::WitNode::PrimS32(value))
193            }
194            Some(wit_node::Value::I64(WitPrimI64Node { value })) => {
195                Ok(super::WitNode::PrimS64(value))
196            }
197            Some(wit_node::Value::F32(WitPrimF32Node { value })) => {
198                Ok(super::WitNode::PrimFloat32(value))
199            }
200            Some(wit_node::Value::F64(WitPrimF64Node { value })) => {
201                Ok(super::WitNode::PrimFloat64(value))
202            }
203            Some(wit_node::Value::Char(WitPrimCharNode { value })) => Ok(super::WitNode::PrimChar(
204                char::from_u32(value)
205                    .ok_or("Protobuf WitPrimCharNode has invalid value".to_string())?,
206            )),
207            Some(wit_node::Value::Bool(WitPrimBoolNode { value })) => {
208                Ok(super::WitNode::PrimBool(value))
209            }
210            Some(wit_node::Value::String(WitPrimStringNode { value })) => {
211                Ok(super::WitNode::PrimString(value))
212            }
213            Some(wit_node::Value::Handle(WitHandleNode { uri, value })) => {
214                Ok(super::WitNode::Handle((super::Uri { value: uri }, value)))
215            }
216        }
217    }
218}
219
220// Conversion from WitValue to protobuf Val
221impl From<super::WitValue> for Val {
222    fn from(value: super::WitValue) -> Self {
223        let value: Value = value.into();
224        value.into()
225    }
226}
227
228impl TryFrom<&ValueAndType> for Type {
229    type Error = String;
230
231    fn try_from(value: &ValueAndType) -> Result<Self, Self::Error> {
232        Ok(value
233            .typ
234            .as_ref()
235            .ok_or_else(|| "Missing typ field".to_string())?
236            .clone())
237    }
238}
239
240impl TryFrom<&ValueAndType> for AnalysedType {
241    type Error = String;
242    fn try_from(value: &ValueAndType) -> Result<Self, Self::Error> {
243        let typ = Type::try_from(value)?;
244        AnalysedType::try_from(&typ)
245    }
246}
247
248impl TryFrom<ValueAndType> for super::WitValue {
249    type Error = String;
250
251    fn try_from(value: ValueAndType) -> Result<Self, Self::Error> {
252        let value: Value = value.try_into()?;
253        Ok(super::WitValue::from(value))
254    }
255}
256
257impl TryFrom<ValueAndType> for Value {
258    type Error = String;
259
260    fn try_from(value: ValueAndType) -> Result<Self, Self::Error> {
261        value
262            .value
263            .ok_or_else(|| "Missing value field".to_string())?
264            .try_into()
265    }
266}
267
268impl From<Value> for Val {
269    fn from(value: Value) -> Self {
270        match value {
271            Value::Bool(value) => Val {
272                val: Some(val::Val::Bool(value)),
273            },
274            Value::U8(value) => Val {
275                val: Some(val::Val::U8(value as i32)),
276            },
277            Value::U16(value) => Val {
278                val: Some(val::Val::U16(value as i32)),
279            },
280            Value::U32(value) => Val {
281                val: Some(val::Val::U32(value as i64)),
282            },
283            Value::U64(value) => Val {
284                val: Some(val::Val::U64(value as i64)),
285            },
286            Value::S8(value) => Val {
287                val: Some(val::Val::S8(value as i32)),
288            },
289            Value::S16(value) => Val {
290                val: Some(val::Val::S16(value as i32)),
291            },
292            Value::S32(value) => Val {
293                val: Some(val::Val::S32(value)),
294            },
295            Value::S64(value) => Val {
296                val: Some(val::Val::S64(value)),
297            },
298            Value::F32(value) => Val {
299                val: Some(val::Val::F32(value)),
300            },
301            Value::F64(value) => Val {
302                val: Some(val::Val::F64(value)),
303            },
304            Value::Char(value) => Val {
305                val: Some(val::Val::Char(value as i32)),
306            },
307            Value::String(value) => Val {
308                val: Some(val::Val::String(value)),
309            },
310            Value::List(items) => Val {
311                val: Some(val::Val::List(ValList {
312                    values: items.into_iter().map(|item| item.into()).collect(),
313                })),
314            },
315            Value::Tuple(items) => Val {
316                val: Some(val::Val::Tuple(ValTuple {
317                    values: items.into_iter().map(|item| item.into()).collect(),
318                })),
319            },
320            Value::Record(fields) => Val {
321                val: Some(val::Val::Record(ValRecord {
322                    values: fields.into_iter().map(|value| value.into()).collect(),
323                })),
324            },
325            Value::Variant {
326                case_idx,
327                case_value,
328            } => Val {
329                val: Some(val::Val::Variant(Box::new(ValVariant {
330                    discriminant: case_idx as i32,
331                    value: case_value.map(|case_value| Box::new((*case_value).into())),
332                }))),
333            },
334            Value::Enum(value) => Val {
335                val: Some(val::Val::Enum(ValEnum {
336                    discriminant: value as i32,
337                })),
338            },
339            Value::Flags(values) => {
340                let mut indexes = Vec::with_capacity(values.len());
341                for (i, value) in values.iter().enumerate() {
342                    if *value {
343                        indexes.push(i as i32);
344                    }
345                }
346                Val {
347                    val: Some(val::Val::Flags(ValFlags {
348                        count: values.len() as i32,
349                        value: indexes,
350                    })),
351                }
352            }
353            Value::Option(Some(value)) => Val {
354                val: Some(val::Val::Option(Box::new(ValOption {
355                    discriminant: 1,
356                    value: Some(Box::new((*value).into())),
357                }))),
358            },
359            Value::Option(None) => Val {
360                val: Some(val::Val::Option(Box::new(ValOption {
361                    discriminant: 0,
362                    value: None,
363                }))),
364            },
365            Value::Result(Ok(value)) => Val {
366                val: Some(val::Val::Result(Box::new(ValResult {
367                    discriminant: 0,
368                    value: value.map(|value| Box::new((*value).into())),
369                }))),
370            },
371            Value::Result(Err(value)) => Val {
372                val: Some(val::Val::Result(Box::new(ValResult {
373                    discriminant: 1,
374                    value: value.map(|value| Box::new((*value).into())),
375                }))),
376            },
377            Value::Handle { uri, resource_id } => Val {
378                val: Some(val::Val::Handle(ValHandle {
379                    uri,
380                    value: resource_id,
381                })),
382            },
383        }
384    }
385}
386
387// Conversion from protobuf Val to WitValue
388impl TryFrom<Val> for super::WitValue {
389    type Error = String;
390
391    fn try_from(value: Val) -> Result<Self, Self::Error> {
392        let value: Value = value.try_into()?;
393        Ok(value.into())
394    }
395}
396
397impl TryFrom<Val> for Value {
398    type Error = String;
399
400    fn try_from(value: Val) -> Result<Self, Self::Error> {
401        match value.val {
402            None => Err("Protobuf Val has no value".to_string()),
403            Some(val::Val::Bool(value)) => Ok(Value::Bool(value)),
404            Some(val::Val::U8(value)) => Ok(Value::U8(value as u8)),
405            Some(val::Val::U16(value)) => Ok(Value::U16(value as u16)),
406            Some(val::Val::U32(value)) => Ok(Value::U32(value as u32)),
407            Some(val::Val::U64(value)) => Ok(Value::U64(value as u64)),
408            Some(val::Val::S8(value)) => Ok(Value::S8(value as i8)),
409            Some(val::Val::S16(value)) => Ok(Value::S16(value as i16)),
410            Some(val::Val::S32(value)) => Ok(Value::S32(value)),
411            Some(val::Val::S64(value)) => Ok(Value::S64(value)),
412            Some(val::Val::F32(value)) => Ok(Value::F32(value)),
413            Some(val::Val::F64(value)) => Ok(Value::F64(value)),
414            Some(val::Val::Char(value)) => Ok(Value::Char(
415                char::from_u32(value as u32)
416                    .ok_or("Protobuf WitPrimCharNode has invalid value".to_string())?,
417            )),
418            Some(val::Val::String(value)) => Ok(Value::String(value)),
419            Some(val::Val::List(ValList { values })) => Ok(Value::List(
420                values
421                    .into_iter()
422                    .map(|value| value.try_into())
423                    .collect::<Result<Vec<_>, _>>()?,
424            )),
425            Some(val::Val::Tuple(ValTuple { values })) => Ok(Value::Tuple(
426                values
427                    .into_iter()
428                    .map(|value| value.try_into())
429                    .collect::<Result<Vec<_>, _>>()?,
430            )),
431            Some(val::Val::Record(ValRecord { values })) => Ok(Value::Record(
432                values
433                    .into_iter()
434                    .map(|value| value.try_into())
435                    .collect::<Result<Vec<_>, _>>()?,
436            )),
437            Some(val::Val::Variant(variant)) => {
438                let discriminant = variant.discriminant as u32;
439                match variant.value {
440                    Some(value) => Ok(Value::Variant {
441                        case_idx: discriminant,
442                        case_value: Some(Box::new((*value).try_into()?)),
443                    }),
444                    None => Ok(Value::Variant {
445                        case_idx: discriminant,
446                        case_value: None,
447                    }),
448                }
449            }
450            Some(val::Val::Enum(ValEnum { discriminant })) => Ok(Value::Enum(discriminant as u32)),
451            Some(val::Val::Flags(ValFlags { count, value })) => {
452                let mut flags = vec![false; count as usize];
453                for i in value {
454                    flags[i as usize] = true;
455                }
456                Ok(Value::Flags(flags))
457            }
458            Some(val::Val::Option(inner)) => {
459                let ValOption {
460                    discriminant,
461                    value,
462                } = *inner;
463                match (discriminant, value) {
464                    (0, None) => Ok(Value::Option(None)),
465                    (1, Some(value)) => Ok(Value::Option(Some(Box::new((*value).try_into()?)))),
466                    _ => Err("Protobuf ValOption has invalid discriminant or value".to_string()),
467                }
468            }
469            Some(val::Val::Result(inner)) => {
470                let ValResult {
471                    discriminant,
472                    value,
473                } = *inner;
474                match (discriminant, value) {
475                    (0, Some(value)) => Ok(Value::Result(Ok(Some(Box::new((*value).try_into()?))))),
476                    (0, None) => Ok(Value::Result(Ok(None))),
477                    (1, Some(value)) => {
478                        Ok(Value::Result(Err(Some(Box::new((*value).try_into()?)))))
479                    }
480                    (1, None) => Ok(Value::Result(Err(None))),
481                    _ => Err("Protobuf ValResult has invalid discriminant or value".to_string()),
482                }
483            }
484            Some(val::Val::Handle(ValHandle { uri, value })) => Ok(Value::Handle {
485                uri,
486                resource_id: value,
487            }),
488        }
489    }
490}
491
492impl From<crate::ValueAndType> for ValueAndType {
493    fn from(value: crate::ValueAndType) -> Self {
494        ValueAndType {
495            value: Some(value.value.into()),
496            typ: Some((&value.typ).into()),
497        }
498    }
499}
500
501impl TryFrom<ValueAndType> for crate::ValueAndType {
502    type Error = String;
503
504    fn try_from(value: ValueAndType) -> Result<Self, Self::Error> {
505        let v: Value = value
506            .value
507            .ok_or_else(|| "Missing value field".to_string())?
508            .try_into()?;
509        let t: AnalysedType =
510            (&value.typ.ok_or_else(|| "Missing typ field".to_string())?).try_into()?;
511        Ok(crate::ValueAndType { value: v, typ: t })
512    }
513}
514
515pub fn function_parameters(
516    parameters: &[Val],
517    expected_parameters: Vec<AnalysedFunctionParameter>,
518) -> Result<(), Vec<String>> {
519    if parameters.len() == expected_parameters.len() {
520        Ok(())
521    } else {
522        Err(vec![format!(
523            "Unexpected number of parameters (got {}, expected: {})",
524            parameters.len(),
525            expected_parameters.len()
526        )])
527    }
528}
529
530#[cfg(test)]
531mod tests {
532    use test_r::test;
533
534    use super::{Val, WitValue};
535    use crate::Value;
536    use proptest::prelude::*;
537    use proptest_arbitrary_interop::arb_sized;
538
539    const CASES: u32 = 10000;
540    const SIZE: usize = 4096;
541
542    proptest! {
543
544        #![proptest_config(ProptestConfig {
545            cases: CASES, .. ProptestConfig::default()
546        })]
547        #[test]
548        fn round_trip_wit_value(value in arb_sized::<Value>(SIZE).prop_filter("Value must be equal to itself", |v| v.eq(v))) {
549            let wit_value: crate::WitValue = value.clone().into();
550            let protobuf_wit_value: WitValue = wit_value.into();
551            let round_trip_wit_value: crate::WitValue = protobuf_wit_value.try_into().unwrap();
552            let round_trip_value: Value = round_trip_wit_value.into();
553            prop_assert_eq!(value, round_trip_value);
554        }
555
556        #[test]
557        fn round_trip_val(value in arb_sized::<Value>(SIZE).prop_filter("Value must be equal to itself", |v| v.eq(v))) {
558            let wit_value: crate::WitValue = value.clone().into();
559
560            let protobuf_val: Val = wit_value.into();
561            let round_trip_wit_value: crate::WitValue = protobuf_val.try_into().unwrap();
562            let round_trip_value: Value = round_trip_wit_value.into();
563            prop_assert_eq!(value, round_trip_value);
564        }
565    }
566}