Skip to main content

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