Skip to main content

rib/
wasm_wave_text.rs

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