Skip to main content

rib/
wasm_wave_text.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::wit_type::WitType;
16use crate::{IntoValueAndType, Value, ValueAndType};
17use std::borrow::Cow;
18use std::collections::HashSet;
19use wasm_wave::wasm::{WasmType, WasmTypeKind, WasmValue, WasmValueError};
20use wasm_wave::{from_str, to_string};
21
22pub fn parse_value_and_type(analysed_type: &WitType, input: &str) -> Result<ValueAndType, String> {
23    let parsed: ValueAndType = from_str(analysed_type, input).map_err(|err| err.to_string())?;
24    Ok(parsed)
25}
26
27pub fn print_value_and_type(value: &ValueAndType) -> Result<String, String> {
28    if value.typ.contains_handle() {
29        Err("Cannot print handle type".to_string())
30    } else {
31        to_string(value).map_err(|err| err.to_string())
32    }
33}
34
35impl WasmValue for ValueAndType {
36    type Type = WitType;
37
38    fn kind(&self) -> WasmTypeKind {
39        self.typ.kind()
40    }
41
42    fn make_bool(val: bool) -> Self {
43        val.into_value_and_type()
44    }
45
46    fn make_s8(val: i8) -> Self {
47        val.into_value_and_type()
48    }
49
50    fn make_s16(val: i16) -> Self {
51        val.into_value_and_type()
52    }
53
54    fn make_s32(val: i32) -> Self {
55        val.into_value_and_type()
56    }
57
58    fn make_s64(val: i64) -> Self {
59        val.into_value_and_type()
60    }
61
62    fn make_u8(val: u8) -> Self {
63        val.into_value_and_type()
64    }
65
66    fn make_u16(val: u16) -> Self {
67        val.into_value_and_type()
68    }
69
70    fn make_u32(val: u32) -> Self {
71        val.into_value_and_type()
72    }
73
74    fn make_u64(val: u64) -> Self {
75        val.into_value_and_type()
76    }
77
78    fn make_f32(val: f32) -> Self {
79        val.into_value_and_type()
80    }
81
82    fn make_f64(val: f64) -> Self {
83        val.into_value_and_type()
84    }
85
86    fn make_char(val: char) -> Self {
87        val.into_value_and_type()
88    }
89
90    fn make_string(val: Cow<str>) -> Self {
91        val.to_string().into_value_and_type()
92    }
93
94    fn make_list(
95        ty: &Self::Type,
96        vals: impl IntoIterator<Item = Self>,
97    ) -> Result<Self, WasmValueError> {
98        Ok(ValueAndType {
99            value: Value::List(vals.into_iter().map(|vnt| vnt.value).collect()),
100            typ: ty.clone(),
101        })
102    }
103
104    fn make_record<'a>(
105        ty: &Self::Type,
106        fields: impl IntoIterator<Item = (&'a str, Self)>,
107    ) -> Result<Self, WasmValueError> {
108        Ok(ValueAndType {
109            value: Value::Record(fields.into_iter().map(|(_, vnt)| vnt.value).collect()),
110            typ: ty.clone(),
111        })
112    }
113
114    fn make_tuple(
115        ty: &Self::Type,
116        vals: impl IntoIterator<Item = Self>,
117    ) -> Result<Self, WasmValueError> {
118        Ok(ValueAndType {
119            value: Value::Tuple(vals.into_iter().map(|vnt| vnt.value).collect()),
120            typ: ty.clone(),
121        })
122    }
123
124    fn make_variant(
125        ty: &Self::Type,
126        case: &str,
127        val: Option<Self>,
128    ) -> Result<Self, WasmValueError> {
129        if let WitType::Variant(typ) = ty {
130            let case_idx = typ
131                .cases
132                .iter()
133                .position(|pair| pair.name == case)
134                .ok_or_else(|| WasmValueError::UnknownCase(case.to_string()))?
135                as u32;
136            Ok(ValueAndType {
137                value: Value::Variant {
138                    case_idx,
139                    case_value: val.map(|vnt| Box::new(vnt.value)),
140                },
141                typ: ty.clone(),
142            })
143        } else {
144            Err(WasmValueError::WrongTypeKind {
145                kind: WasmTypeKind::Variant,
146                ty: ty.kind().to_string(),
147            })
148        }
149    }
150
151    fn make_enum(ty: &Self::Type, case: &str) -> Result<Self, WasmValueError> {
152        if let WitType::Enum(typ) = ty {
153            let case_idx = typ
154                .cases
155                .iter()
156                .position(|c| c == case)
157                .ok_or_else(|| WasmValueError::UnknownCase(case.to_string()))?
158                as u32;
159            Ok(ValueAndType {
160                value: Value::Enum(case_idx),
161                typ: ty.clone(),
162            })
163        } else {
164            Err(WasmValueError::WrongTypeKind {
165                kind: WasmTypeKind::Enum,
166                ty: ty.kind().to_string(),
167            })
168        }
169    }
170
171    fn make_option(ty: &Self::Type, val: Option<Self>) -> Result<Self, WasmValueError> {
172        Ok(ValueAndType {
173            value: Value::Option(val.map(|vnt| Box::new(vnt.value))),
174            typ: ty.clone(),
175        })
176    }
177
178    fn make_result(
179        ty: &Self::Type,
180        val: Result<Option<Self>, Option<Self>>,
181    ) -> Result<Self, WasmValueError> {
182        Ok(ValueAndType {
183            value: Value::Result(
184                val.map(|maybe_ok| maybe_ok.map(|vnt| Box::new(vnt.value)))
185                    .map_err(|maybe_err| maybe_err.map(|vnt| Box::new(vnt.value))),
186            ),
187            typ: ty.clone(),
188        })
189    }
190
191    fn make_flags<'a>(
192        ty: &Self::Type,
193        names: impl IntoIterator<Item = &'a str>,
194    ) -> Result<Self, WasmValueError> {
195        if let WitType::Flags(typ) = ty {
196            let mut bitmap = Vec::new();
197            let names: HashSet<&'a str> = HashSet::from_iter(names);
198            for name in &typ.names {
199                bitmap.push(names.contains(name.as_str()));
200            }
201            Ok(ValueAndType {
202                value: Value::Flags(bitmap),
203                typ: ty.clone(),
204            })
205        } else {
206            Err(WasmValueError::WrongTypeKind {
207                kind: WasmTypeKind::Flags,
208                ty: ty.kind().to_string(),
209            })
210        }
211    }
212
213    fn unwrap_bool(&self) -> bool {
214        match self.value {
215            Value::Bool(val) => val,
216            _ => panic!("Expected bool, found {self:?}"),
217        }
218    }
219
220    fn unwrap_s8(&self) -> i8 {
221        match self.value {
222            Value::S8(val) => val,
223            _ => panic!("Expected s8, found {self:?}"),
224        }
225    }
226
227    fn unwrap_s16(&self) -> i16 {
228        match self.value {
229            Value::S16(val) => val,
230            _ => panic!("Expected s16, found {self:?}"),
231        }
232    }
233
234    fn unwrap_s32(&self) -> i32 {
235        match self.value {
236            Value::S32(val) => val,
237            _ => panic!("Expected s32, found {self:?}"),
238        }
239    }
240
241    fn unwrap_s64(&self) -> i64 {
242        match self.value {
243            Value::S64(val) => val,
244            _ => panic!("Expected s64, found {self:?}"),
245        }
246    }
247
248    fn unwrap_u8(&self) -> u8 {
249        match self.value {
250            Value::U8(val) => val,
251            _ => panic!("Expected u8, found {self:?}"),
252        }
253    }
254
255    fn unwrap_u16(&self) -> u16 {
256        match self.value {
257            Value::U16(val) => val,
258            _ => panic!("Expected u16, found {self:?}"),
259        }
260    }
261
262    fn unwrap_u32(&self) -> u32 {
263        match self.value {
264            Value::U32(val) => val,
265            _ => panic!("Expected u32, found {self:?}"),
266        }
267    }
268
269    fn unwrap_u64(&self) -> u64 {
270        match self.value {
271            Value::U64(val) => val,
272            _ => panic!("Expected u64, found {self:?}"),
273        }
274    }
275
276    fn unwrap_f32(&self) -> f32 {
277        match self.value {
278            Value::F32(val) => val,
279            _ => panic!("Expected f32, found {self:?}"),
280        }
281    }
282
283    fn unwrap_f64(&self) -> f64 {
284        match self.value {
285            Value::F64(val) => val,
286            _ => panic!("Expected f64, found {self:?}"),
287        }
288    }
289
290    fn unwrap_char(&self) -> char {
291        match self.value {
292            Value::Char(val) => val,
293            _ => panic!("Expected char, found {self:?}"),
294        }
295    }
296
297    fn unwrap_string(&self) -> Cow<'_, str> {
298        match &self.value {
299            Value::String(val) => Cow::Borrowed(val),
300            _ => panic!("Expected string, found {self:?}"),
301        }
302    }
303
304    fn unwrap_list(&self) -> Box<dyn Iterator<Item = Cow<'_, Self>> + '_> {
305        match (&self.value, &self.typ) {
306            (Value::List(vals), WitType::List(typ)) => Box::new(vals.iter().map(|val| {
307                Cow::Owned(ValueAndType {
308                    value: val.clone(),
309                    typ: (*typ.inner).clone(),
310                })
311            })),
312            _ => panic!("Expected list, found {self:?}"),
313        }
314    }
315
316    fn unwrap_record(&self) -> Box<dyn Iterator<Item = (Cow<'_, str>, Cow<'_, Self>)> + '_> {
317        match (&self.value, &self.typ) {
318            (Value::Record(vals), WitType::Record(typ)) => {
319                Box::new(vals.iter().zip(typ.fields.iter()).map(|(val, field)| {
320                    (
321                        Cow::Borrowed(field.name.as_str()),
322                        Cow::Owned(ValueAndType {
323                            value: val.clone(),
324                            typ: field.typ.clone(),
325                        }),
326                    )
327                }))
328            }
329            _ => panic!("Expected record, found {self:?}"),
330        }
331    }
332
333    fn unwrap_tuple(&self) -> Box<dyn Iterator<Item = Cow<'_, Self>> + '_> {
334        match (&self.value, &self.typ) {
335            (Value::Tuple(vals), WitType::Tuple(typ)) => {
336                Box::new(vals.iter().zip(typ.items.iter()).map(|(val, ty)| {
337                    Cow::Owned(ValueAndType {
338                        value: val.clone(),
339                        typ: ty.clone(),
340                    })
341                }))
342            }
343            _ => panic!("Expected tuple, found {self:?}"),
344        }
345    }
346
347    fn unwrap_variant(&self) -> (Cow<'_, str>, Option<Cow<'_, Self>>) {
348        match (&self.value, &self.typ) {
349            (
350                Value::Variant {
351                    case_idx,
352                    case_value,
353                },
354                WitType::Variant(typ),
355            ) => {
356                let case = &typ.cases[*case_idx as usize];
357                (
358                    Cow::Borrowed(case.name.as_str()),
359                    case_value.as_ref().map(|val| {
360                        Cow::Owned(ValueAndType {
361                            value: *val.clone(),
362                            typ: case.typ.clone().unwrap(),
363                        })
364                    }),
365                )
366            }
367            _ => panic!("Expected variant, found {self:?}"),
368        }
369    }
370
371    fn unwrap_enum(&self) -> Cow<'_, str> {
372        match (&self.value, &self.typ) {
373            (Value::Enum(case_idx), WitType::Enum(typ)) => {
374                Cow::Borrowed(&typ.cases[*case_idx as usize])
375            }
376            _ => panic!("Expected enum, found {self:?}"),
377        }
378    }
379
380    fn unwrap_option(&self) -> Option<Cow<'_, Self>> {
381        match (&self.value, &self.typ) {
382            (Value::Option(Some(val)), WitType::Option(typ)) => Some(Cow::Owned(ValueAndType {
383                value: *val.clone(),
384                typ: (*typ.inner).clone(),
385            })),
386            (Value::Option(None), WitType::Option(_)) => None,
387            _ => panic!("Expected option, found {self:?}"),
388        }
389    }
390
391    fn unwrap_result(&self) -> Result<Option<Cow<'_, Self>>, Option<Cow<'_, Self>>> {
392        match (&self.value, &self.typ) {
393            (Value::Result(Ok(Some(val))), WitType::Result(typ)) => {
394                Ok(Some(Cow::Owned(ValueAndType {
395                    value: *val.clone(),
396                    typ: *typ
397                        .ok
398                        .as_ref()
399                        .expect("No type information for non-unit ok value")
400                        .clone(),
401                })))
402            }
403            (Value::Result(Ok(None)), WitType::Result(_)) => Ok(None),
404            (Value::Result(Err(Some(val))), WitType::Result(typ)) => {
405                Err(Some(Cow::Owned(ValueAndType {
406                    value: *val.clone(),
407                    typ: *typ
408                        .err
409                        .as_ref()
410                        .expect("No type information for non-unit error value")
411                        .clone(),
412                })))
413            }
414            (Value::Result(Err(None)), WitType::Result(_)) => Err(None),
415            _ => panic!("Expected result, found {self:?}"),
416        }
417    }
418
419    fn unwrap_flags(&self) -> Box<dyn Iterator<Item = Cow<'_, str>> + '_> {
420        match (&self.value, &self.typ) {
421            (Value::Flags(bitmap), WitType::Flags(typ)) => Box::new(
422                bitmap
423                    .iter()
424                    .zip(typ.names.iter())
425                    .filter_map(|(is_set, name)| {
426                        if *is_set {
427                            Some(Cow::Borrowed(name.as_str()))
428                        } else {
429                            None
430                        }
431                    }),
432            ),
433            _ => panic!("Expected flags, found {self:?}"),
434        }
435    }
436}