wasm_wave/value/
mod.rs

1//! Value enum for WAVE values.
2
3mod convert;
4#[cfg(test)]
5mod tests;
6mod ty;
7
8mod func;
9#[cfg(feature = "wit")]
10mod wit;
11
12#[cfg(feature = "wit")]
13pub use wit::{resolve_wit_func_type, resolve_wit_type};
14
15use std::{borrow::Cow, collections::HashMap, sync::Arc};
16
17use crate::{
18    canonicalize_nan32, canonicalize_nan64,
19    wasm::{
20        WasmType, WasmTypeKind, WasmValue, WasmValueError, ensure_type_kind, maybe_unwrap_type,
21        unwrap_val,
22    },
23};
24
25use self::ty::{
26    EnumType, FlagsType, ListType, OptionType, RecordType, ResultType, TupleType, TypeEnum,
27    VariantType,
28};
29
30pub use self::func::FuncType;
31pub use self::ty::Type;
32
33/// A Value is a WAVE value, and implements [`WasmValue`].
34#[derive(Debug, Clone, PartialEq)]
35pub struct Value(ValueEnum);
36
37#[derive(Debug, Clone, PartialEq)]
38pub(super) enum ValueEnum {
39    Bool(bool),
40    S8(i8),
41    U8(u8),
42    S16(i16),
43    U16(u16),
44    S32(i32),
45    U32(u32),
46    S64(i64),
47    U64(u64),
48    F32(f32),
49    F64(f64),
50    Char(char),
51    String(Box<str>),
52    List(List),
53    Record(Record),
54    Tuple(Tuple),
55    Variant(Variant),
56    Enum(Enum),
57    Option(OptionValue),
58    Result(ResultValue),
59    Flags(Flags),
60}
61
62#[derive(Debug, Clone, PartialEq)]
63#[doc(hidden)]
64pub struct List {
65    ty: Arc<ListType>,
66    elements: Vec<Value>,
67}
68
69#[derive(Debug, Clone, PartialEq)]
70#[doc(hidden)]
71pub struct Record {
72    ty: Arc<RecordType>,
73    fields: Vec<Value>,
74}
75
76#[derive(Debug, Clone, PartialEq)]
77#[doc(hidden)]
78pub struct Tuple {
79    ty: Arc<TupleType>,
80    elements: Vec<Value>,
81}
82
83#[derive(Debug, Clone, PartialEq)]
84#[doc(hidden)]
85pub struct Variant {
86    ty: Arc<VariantType>,
87    case: usize,
88    payload: Option<Box<Value>>,
89}
90
91#[derive(Debug, Clone, PartialEq)]
92#[doc(hidden)]
93pub struct Enum {
94    ty: Arc<EnumType>,
95    case: usize,
96}
97
98#[derive(Debug, Clone, PartialEq)]
99#[doc(hidden)]
100pub struct OptionValue {
101    ty: Arc<OptionType>,
102    value: Option<Box<Value>>,
103}
104
105#[derive(Debug, Clone, PartialEq)]
106#[doc(hidden)]
107pub struct ResultValue {
108    ty: Arc<ResultType>,
109    value: Result<Option<Box<Value>>, Option<Box<Value>>>,
110}
111
112#[derive(Debug, Clone, PartialEq)]
113#[doc(hidden)]
114pub struct Flags {
115    ty: Arc<FlagsType>,
116    flags: Vec<usize>,
117}
118
119macro_rules! impl_primitives {
120    ($Self:ident, $(($case:ident, $ty:ty, $make:ident, $unwrap:ident)),*) => {
121        $(
122            fn $make(val: $ty) -> $Self {
123                $Self(ValueEnum::$case(val))
124            }
125
126            fn $unwrap(&self) -> $ty {
127                *unwrap_val!(&self.0, ValueEnum::$case, stringify!($case))
128            }
129        )*
130    };
131}
132
133impl WasmValue for Value {
134    type Type = Type;
135
136    fn kind(&self) -> WasmTypeKind {
137        match &self.0 {
138            ValueEnum::Bool(_) => WasmTypeKind::Bool,
139            ValueEnum::S8(_) => WasmTypeKind::S8,
140            ValueEnum::S16(_) => WasmTypeKind::S16,
141            ValueEnum::S32(_) => WasmTypeKind::S32,
142            ValueEnum::S64(_) => WasmTypeKind::S64,
143            ValueEnum::U8(_) => WasmTypeKind::U8,
144            ValueEnum::U16(_) => WasmTypeKind::U16,
145            ValueEnum::U32(_) => WasmTypeKind::U32,
146            ValueEnum::U64(_) => WasmTypeKind::U64,
147            ValueEnum::F32(_) => WasmTypeKind::F32,
148            ValueEnum::F64(_) => WasmTypeKind::F64,
149            ValueEnum::Char(_) => WasmTypeKind::Char,
150            ValueEnum::String(_) => WasmTypeKind::String,
151            ValueEnum::List(_) => WasmTypeKind::List,
152            ValueEnum::Record(_) => WasmTypeKind::Record,
153            ValueEnum::Tuple(_) => WasmTypeKind::Tuple,
154            ValueEnum::Variant(_) => WasmTypeKind::Variant,
155            ValueEnum::Enum(_) => WasmTypeKind::Enum,
156            ValueEnum::Option(_) => WasmTypeKind::Option,
157            ValueEnum::Result(_) => WasmTypeKind::Result,
158            ValueEnum::Flags(_) => WasmTypeKind::Flags,
159        }
160    }
161
162    impl_primitives!(
163        Self,
164        (Bool, bool, make_bool, unwrap_bool),
165        (S8, i8, make_s8, unwrap_s8),
166        (S16, i16, make_s16, unwrap_s16),
167        (S32, i32, make_s32, unwrap_s32),
168        (S64, i64, make_s64, unwrap_s64),
169        (U8, u8, make_u8, unwrap_u8),
170        (U16, u16, make_u16, unwrap_u16),
171        (U32, u32, make_u32, unwrap_u32),
172        (U64, u64, make_u64, unwrap_u64),
173        (Char, char, make_char, unwrap_char)
174    );
175
176    fn make_f32(val: f32) -> Self {
177        let val = canonicalize_nan32(val);
178        Self(ValueEnum::F32(val))
179    }
180
181    fn make_f64(val: f64) -> Self {
182        let val = canonicalize_nan64(val);
183        Self(ValueEnum::F64(val))
184    }
185
186    fn make_string(val: std::borrow::Cow<str>) -> Self {
187        Self(ValueEnum::String(val.into()))
188    }
189
190    fn make_list(
191        ty: &Self::Type,
192        vals: impl IntoIterator<Item = Self>,
193    ) -> Result<Self, WasmValueError> {
194        ensure_type_kind(ty, WasmTypeKind::List)?;
195        let element_type = ty.list_element_type().unwrap();
196        let elements = vals
197            .into_iter()
198            .map(|v| check_type(&element_type, v))
199            .collect::<Result<_, _>>()?;
200        let ty = maybe_unwrap_type!(&ty.0, TypeEnum::List).unwrap().clone();
201        Ok(Self(ValueEnum::List(List { ty, elements })))
202    }
203
204    fn make_record<'a>(
205        ty: &Self::Type,
206        fields: impl IntoIterator<Item = (&'a str, Self)>,
207    ) -> Result<Self, WasmValueError> {
208        ensure_type_kind(ty, WasmTypeKind::Record)?;
209        let mut field_vals: HashMap<_, _> = fields.into_iter().collect();
210        let mut fields = Vec::with_capacity(field_vals.len());
211        for (name, ty) in ty.record_fields() {
212            let val = field_vals
213                .remove(&*name)
214                .ok_or_else(|| WasmValueError::MissingField(name.into()))?;
215            fields.push(check_type(&ty, val)?);
216        }
217        if let Some(unknown) = field_vals.into_keys().next() {
218            return Err(WasmValueError::UnknownField(unknown.into()));
219        }
220        let ty = maybe_unwrap_type!(&ty.0, TypeEnum::Record).unwrap().clone();
221        Ok(Self(ValueEnum::Record(Record { ty, fields })))
222    }
223
224    fn make_tuple(
225        ty: &Self::Type,
226        vals: impl IntoIterator<Item = Self>,
227    ) -> Result<Self, WasmValueError> {
228        ensure_type_kind(ty, WasmTypeKind::Tuple)?;
229        let types = ty.tuple_element_types().collect::<Vec<_>>();
230        let elements = Vec::from_iter(vals);
231        if types.len() != elements.len() {
232            return Err(WasmValueError::WrongNumberOfTupleValues {
233                want: types.len(),
234                got: elements.len(),
235            });
236        }
237        for (ty, val) in types.iter().zip(&elements) {
238            check_type2(ty, val)?;
239        }
240        let ty = maybe_unwrap_type!(&ty.0, TypeEnum::Tuple).unwrap().clone();
241        Ok(Self(ValueEnum::Tuple(Tuple { ty, elements })))
242    }
243
244    fn make_variant(
245        ty: &Self::Type,
246        case_name: &str,
247        val: Option<Self>,
248    ) -> Result<Self, WasmValueError> {
249        ensure_type_kind(ty, WasmTypeKind::Variant)?;
250        let (case, payload_type) = ty
251            .variant_cases()
252            .enumerate()
253            .find_map(|(idx, (name, ty))| (name == case_name).then_some((idx, ty)))
254            .ok_or_else(|| WasmValueError::UnknownCase(case_name.into()))?;
255        let payload = check_payload_type(case_name, &payload_type, val)?;
256        let ty = maybe_unwrap_type!(&ty.0, TypeEnum::Variant)
257            .unwrap()
258            .clone();
259        Ok(Self(ValueEnum::Variant(Variant { ty, case, payload })))
260    }
261
262    fn make_enum(ty: &Self::Type, case: &str) -> Result<Self, WasmValueError> {
263        ensure_type_kind(ty, WasmTypeKind::Enum)?;
264        let case = ty
265            .enum_cases()
266            .position(|name| name == case)
267            .ok_or_else(|| WasmValueError::UnknownCase(case.into()))?;
268        let ty = maybe_unwrap_type!(&ty.0, TypeEnum::Enum).unwrap().clone();
269        Ok(Self(ValueEnum::Enum(Enum { ty, case })))
270    }
271
272    fn make_option(ty: &Self::Type, val: Option<Self>) -> Result<Self, WasmValueError> {
273        ensure_type_kind(ty, WasmTypeKind::Option)?;
274        let value = match val {
275            Some(val) => Some(Box::new(check_type(&ty.option_some_type().unwrap(), val)?)),
276            None => None,
277        };
278        let ty = maybe_unwrap_type!(&ty.0, TypeEnum::Option).unwrap().clone();
279        Ok(Self(ValueEnum::Option(OptionValue { ty, value })))
280    }
281
282    fn make_result(
283        ty: &Self::Type,
284        val: Result<Option<Self>, Option<Self>>,
285    ) -> Result<Self, WasmValueError> {
286        ensure_type_kind(ty, WasmTypeKind::Result)?;
287        let (ok_type, err_type) = ty.result_types().unwrap();
288        let value = match val {
289            Ok(ok) => Ok(check_payload_type("ok", &ok_type, ok)?),
290            Err(err) => Err(check_payload_type("err", &err_type, err)?),
291        };
292        let ty = maybe_unwrap_type!(&ty.0, TypeEnum::Result).unwrap().clone();
293        Ok(Self(ValueEnum::Result(ResultValue { ty, value })))
294    }
295
296    fn make_flags<'a>(
297        ty: &Self::Type,
298        names: impl IntoIterator<Item = &'a str>,
299    ) -> Result<Self, WasmValueError> {
300        ensure_type_kind(ty, WasmTypeKind::Flags)?;
301        let flag_names = ty.flags_names().collect::<Vec<_>>();
302        let mut flags = names
303            .into_iter()
304            .map(|name| {
305                flag_names
306                    .iter()
307                    .position(|flag| flag == name)
308                    .ok_or_else(|| WasmValueError::UnknownCase(name.into()))
309            })
310            .collect::<Result<Vec<_>, WasmValueError>>()?;
311        // Flags values don't logically contain an ordering of the flags. Sort
312        // the flags values so that equivalent flags values compare equal.
313        flags.sort();
314        let ty = maybe_unwrap_type!(&ty.0, TypeEnum::Flags).unwrap().clone();
315        Ok(Self(ValueEnum::Flags(Flags { ty, flags })))
316    }
317
318    fn unwrap_f32(&self) -> f32 {
319        let val = *unwrap_val!(&self.0, ValueEnum::F32, "f32");
320        canonicalize_nan32(val)
321    }
322
323    fn unwrap_f64(&self) -> f64 {
324        let val = *unwrap_val!(&self.0, ValueEnum::F64, "f64");
325        canonicalize_nan64(val)
326    }
327
328    fn unwrap_string(&self) -> std::borrow::Cow<'_, str> {
329        unwrap_val!(&self.0, ValueEnum::String, "string")
330            .as_ref()
331            .into()
332    }
333    fn unwrap_list(&self) -> Box<dyn Iterator<Item = Cow<'_, Self>> + '_> {
334        let list = unwrap_val!(&self.0, ValueEnum::List, "list");
335        Box::new(list.elements.iter().map(cow))
336    }
337    fn unwrap_record(&self) -> Box<dyn Iterator<Item = (Cow<'_, str>, Cow<'_, Self>)> + '_> {
338        let record = unwrap_val!(&self.0, ValueEnum::Record, "record");
339        Box::new(
340            record
341                .ty
342                .fields
343                .iter()
344                .map(|(name, _)| cow(name.as_ref()))
345                .zip(record.fields.iter().map(cow)),
346        )
347    }
348    fn unwrap_tuple(&self) -> Box<dyn Iterator<Item = Cow<'_, Self>> + '_> {
349        let tuple = unwrap_val!(&self.0, ValueEnum::Tuple, "tuple");
350        Box::new(tuple.elements.iter().map(cow))
351    }
352    fn unwrap_variant(&self) -> (Cow<'_, str>, Option<Cow<'_, Self>>) {
353        let variant = unwrap_val!(&self.0, ValueEnum::Variant, "variant");
354        let (ref name, _) = variant.ty.cases[variant.case];
355        (cow(name.as_ref()), variant.payload.as_deref().map(cow))
356    }
357    fn unwrap_enum(&self) -> Cow<'_, str> {
358        let enum_ = unwrap_val!(&self.0, ValueEnum::Enum, "enum");
359        cow(enum_.ty.cases[enum_.case].as_ref())
360    }
361    fn unwrap_option(&self) -> Option<Cow<'_, Self>> {
362        unwrap_val!(&self.0, ValueEnum::Option, "option")
363            .value
364            .as_ref()
365            .map(|v| cow(v.as_ref()))
366    }
367    fn unwrap_result(&self) -> Result<Option<Cow<'_, Self>>, Option<Cow<'_, Self>>> {
368        match &unwrap_val!(&self.0, ValueEnum::Result, "result").value {
369            Ok(val) => Ok(val.as_deref().map(cow)),
370            Err(val) => Err(val.as_deref().map(cow)),
371        }
372    }
373    fn unwrap_flags(&self) -> Box<dyn Iterator<Item = Cow<'_, str>> + '_> {
374        let flags = unwrap_val!(&self.0, ValueEnum::Flags, "flags");
375        Box::new(
376            flags
377                .flags
378                .iter()
379                .map(|idx| cow(flags.ty.flags[*idx].as_ref())),
380        )
381    }
382}
383
384fn cow<T: ToOwned + ?Sized>(t: &T) -> Cow<'_, T> {
385    Cow::Borrowed(t)
386}
387
388fn check_type(expected: &Type, val: Value) -> Result<Value, WasmValueError> {
389    check_type2(expected, &val)?;
390    Ok(val)
391}
392
393fn check_type2(expected: &Type, val: &Value) -> Result<(), WasmValueError> {
394    let wrong_value_type =
395        || -> Result<(), WasmValueError> { Err(WasmValueError::wrong_value_type(expected, val)) };
396
397    match (&val.0, expected) {
398        (ValueEnum::Bool(_), &Type::BOOL) => {}
399        (ValueEnum::S8(_), &Type::S8) => {}
400        (ValueEnum::S16(_), &Type::S16) => {}
401        (ValueEnum::S32(_), &Type::S32) => {}
402        (ValueEnum::S64(_), &Type::S64) => {}
403        (ValueEnum::U8(_), &Type::U8) => {}
404        (ValueEnum::U16(_), &Type::U16) => {}
405        (ValueEnum::U32(_), &Type::U32) => {}
406        (ValueEnum::U64(_), &Type::U64) => {}
407        (ValueEnum::F32(_), &Type::F32) => {}
408        (ValueEnum::F64(_), &Type::F64) => {}
409        (ValueEnum::Char(_), &Type::CHAR) => {}
410        (ValueEnum::String(_), &Type::STRING) => {}
411        (ValueEnum::List(list), _) => {
412            if let TypeEnum::List(list_type) = &expected.0 {
413                let ty = &list_type.element;
414                if ty != &list.ty.element {
415                    return wrong_value_type();
416                }
417                for v in &list.elements {
418                    check_type2(ty, v)?;
419                }
420            } else {
421                return wrong_value_type();
422            }
423        }
424        (ValueEnum::Record(record), _) => {
425            if let TypeEnum::Record(record_type) = &expected.0 {
426                if record.ty.as_ref() != record_type.as_ref() {
427                    return wrong_value_type();
428                }
429                let expected_element_types = &record_type.fields;
430                if expected_element_types != &record.ty.fields {
431                    return wrong_value_type();
432                }
433                if expected_element_types.len() != record.fields.len() {
434                    return wrong_value_type();
435                }
436
437                for (field_ty, val) in expected_element_types.as_ref().iter().zip(&record.fields) {
438                    check_type2(&field_ty.1, val)?;
439                }
440            } else {
441                return wrong_value_type();
442            }
443        }
444        (ValueEnum::Tuple(tuple), _) => {
445            if let TypeEnum::Tuple(tuple_type) = &expected.0 {
446                let expected_element_types = &tuple_type.elements;
447                if expected_element_types != &tuple.ty.elements {
448                    return wrong_value_type();
449                }
450                if expected_element_types.len() != tuple.elements.len() {
451                    return wrong_value_type();
452                }
453
454                for (ty, val) in expected_element_types.as_ref().iter().zip(&tuple.elements) {
455                    check_type2(ty, val)?;
456                }
457            } else {
458                return wrong_value_type();
459            }
460        }
461        (ValueEnum::Variant(variant), _) => {
462            if let TypeEnum::Variant(variant_type) = &expected.0 {
463                if variant.ty.cases != variant_type.cases {
464                    return wrong_value_type();
465                }
466                if variant.case >= variant.ty.cases.len() {
467                    return wrong_value_type();
468                }
469                match (&variant.ty.cases[variant.case].1, &variant.payload) {
470                    (None, None) => {}
471                    (Some(t), Some(v)) => check_type2(t, v)?,
472                    _ => return wrong_value_type(),
473                }
474            } else {
475                return wrong_value_type();
476            }
477        }
478        (ValueEnum::Enum(enm), _) => {
479            if let TypeEnum::Enum(enum_type) = &expected.0 {
480                if enm.case >= enm.ty.cases.len() {
481                    return wrong_value_type();
482                }
483                if enm.ty.cases != enum_type.cases {
484                    return wrong_value_type();
485                }
486            } else {
487                return wrong_value_type();
488            }
489        }
490        (ValueEnum::Option(option), _) => {
491            if let TypeEnum::Option(option_type) = &expected.0 {
492                if option.ty.as_ref().some != option_type.some {
493                    return wrong_value_type();
494                }
495                if let Some(v) = option.value.as_ref() {
496                    check_type2(&option_type.some, v)?;
497                }
498            } else {
499                return wrong_value_type();
500            }
501        }
502        (ValueEnum::Result(result), _) => {
503            if let TypeEnum::Result(result_type) = &expected.0 {
504                if result.ty.as_ref() != result_type.as_ref() {
505                    return wrong_value_type();
506                }
507                match &result.value {
508                    Ok(o) => match (&o, &result_type.ok) {
509                        (None, None) => {}
510                        (Some(v), Some(t)) => check_type2(t, v)?,
511                        _ => return wrong_value_type(),
512                    },
513                    Err(e) => match (&e, &result_type.err) {
514                        (None, None) => {}
515                        (Some(v), Some(t)) => check_type2(t, v)?,
516                        _ => return wrong_value_type(),
517                    },
518                }
519            } else {
520                return wrong_value_type();
521            }
522        }
523        (ValueEnum::Flags(flags), _) => {
524            if let TypeEnum::Flags(flags_type) = &expected.0 {
525                if flags.ty.as_ref() != flags_type.as_ref() {
526                    return wrong_value_type();
527                }
528                for flag in &flags.flags {
529                    if *flag >= flags.ty.as_ref().flags.len() {
530                        return wrong_value_type();
531                    }
532                }
533            } else {
534                return wrong_value_type();
535            }
536        }
537        (_, _) => return wrong_value_type(),
538    };
539    Ok(())
540}
541
542fn check_payload_type(
543    name: &str,
544    expected: &Option<Type>,
545    val: Option<Value>,
546) -> Result<Option<Box<Value>>, WasmValueError> {
547    match (expected, val) {
548        (Some(payload_type), Some(val)) => Ok(Some(Box::new(check_type(payload_type, val)?))),
549        (None, None) => Ok(None),
550        (Some(_), None) => Err(WasmValueError::MissingPayload(name.into())),
551        (None, Some(_)) => Err(WasmValueError::UnexpectedPayload(name.into())),
552    }
553}