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