1 use crate::component;
2 use crate::prelude::*;
3 use std::borrow::Cow;
4 
5 use super::{canonicalize_nan32, canonicalize_nan64, unwrap_2val, unwrap_val};
6 use component::wasm_wave::wasm::{
7     DisplayValue, WasmFunc, WasmType, WasmTypeKind, WasmValue, WasmValueError, ensure_type_kind,
8 };
9 
10 macro_rules! maybe_unwrap_type {
11     ($ty:expr, $case:path) => {
12         match $ty {
13             $case(v) => Some(v),
14             _ => None,
15         }
16     };
17 }
18 
19 impl WasmType for component::Type {
kind(&self) -> WasmTypeKind20     fn kind(&self) -> WasmTypeKind {
21         match self {
22             Self::Bool => WasmTypeKind::Bool,
23             Self::S8 => WasmTypeKind::S8,
24             Self::U8 => WasmTypeKind::U8,
25             Self::S16 => WasmTypeKind::S16,
26             Self::U16 => WasmTypeKind::U16,
27             Self::S32 => WasmTypeKind::S32,
28             Self::U32 => WasmTypeKind::U32,
29             Self::S64 => WasmTypeKind::S64,
30             Self::U64 => WasmTypeKind::U64,
31             Self::Float32 => WasmTypeKind::F32,
32             Self::Float64 => WasmTypeKind::F64,
33             Self::Char => WasmTypeKind::Char,
34             Self::String => WasmTypeKind::String,
35             Self::List(_) => WasmTypeKind::List,
36             Self::Record(_) => WasmTypeKind::Record,
37             Self::Tuple(_) => WasmTypeKind::Tuple,
38             Self::Variant(_) => WasmTypeKind::Variant,
39             Self::Enum(_) => WasmTypeKind::Enum,
40             Self::Option(_) => WasmTypeKind::Option,
41             Self::Result(_) => WasmTypeKind::Result,
42             Self::Flags(_) => WasmTypeKind::Flags,
43 
44             Self::Own(_)
45             | Self::Borrow(_)
46             | Self::Stream(_)
47             | Self::Future(_)
48             | Self::ErrorContext
49             | Self::Map(_) => WasmTypeKind::Unsupported,
50         }
51     }
52 
list_element_type(&self) -> Option<Self>53     fn list_element_type(&self) -> Option<Self> {
54         Some(maybe_unwrap_type!(self, Self::List)?.ty())
55     }
56 
record_fields(&self) -> Box<dyn Iterator<Item = (Cow<'_, str>, Self)> + '_>57     fn record_fields(&self) -> Box<dyn Iterator<Item = (Cow<'_, str>, Self)> + '_> {
58         let Self::Record(record) = self else {
59             return Box::new(std::iter::empty());
60         };
61         Box::new(record.fields().map(|f| (f.name.into(), f.ty.clone())))
62     }
63 
tuple_element_types(&self) -> Box<dyn Iterator<Item = Self> + '_>64     fn tuple_element_types(&self) -> Box<dyn Iterator<Item = Self> + '_> {
65         let Self::Tuple(tuple) = self else {
66             return Box::new(std::iter::empty());
67         };
68         Box::new(tuple.types())
69     }
70 
variant_cases(&self) -> Box<dyn Iterator<Item = (Cow<'_, str>, Option<Self>)> + '_>71     fn variant_cases(&self) -> Box<dyn Iterator<Item = (Cow<'_, str>, Option<Self>)> + '_> {
72         let Self::Variant(variant) = self else {
73             return Box::new(std::iter::empty());
74         };
75         Box::new(variant.cases().map(|case| (case.name.into(), case.ty)))
76     }
77 
enum_cases(&self) -> Box<dyn Iterator<Item = Cow<'_, str>> + '_>78     fn enum_cases(&self) -> Box<dyn Iterator<Item = Cow<'_, str>> + '_> {
79         let Self::Enum(enum_) = self else {
80             return Box::new(std::iter::empty());
81         };
82         Box::new(enum_.names().map(Into::into))
83     }
84 
option_some_type(&self) -> Option<Self>85     fn option_some_type(&self) -> Option<Self> {
86         maybe_unwrap_type!(self, Self::Option).map(|o| o.ty())
87     }
88 
result_types(&self) -> Option<(Option<Self>, Option<Self>)>89     fn result_types(&self) -> Option<(Option<Self>, Option<Self>)> {
90         let result = maybe_unwrap_type!(self, Self::Result)?;
91         Some((result.ok(), result.err()))
92     }
93 
flags_names(&self) -> Box<dyn Iterator<Item = Cow<'_, str>> + '_>94     fn flags_names(&self) -> Box<dyn Iterator<Item = Cow<'_, str>> + '_> {
95         let Self::Flags(flags) = self else {
96             return Box::new(std::iter::empty());
97         };
98         Box::new(flags.names().map(Into::into))
99     }
100 }
101 
102 macro_rules! impl_primitives {
103     ($Self:ident, $(($case:ident, $ty:ty, $make:ident, $unwrap:ident)),*) => {
104         $(
105             fn $make(val: $ty) -> $Self {
106                 $Self::$case(val)
107             }
108 
109             fn $unwrap(&self) -> $ty {
110                 *unwrap_val!(self, $Self::$case, stringify!($case))
111             }
112         )*
113     };
114 }
115 
116 impl WasmValue for component::Val {
117     type Type = component::Type;
118 
kind(&self) -> WasmTypeKind119     fn kind(&self) -> WasmTypeKind {
120         match self {
121             Self::Bool(_) => WasmTypeKind::Bool,
122             Self::S8(_) => WasmTypeKind::S8,
123             Self::U8(_) => WasmTypeKind::U8,
124             Self::S16(_) => WasmTypeKind::S16,
125             Self::U16(_) => WasmTypeKind::U16,
126             Self::S32(_) => WasmTypeKind::S32,
127             Self::U32(_) => WasmTypeKind::U32,
128             Self::S64(_) => WasmTypeKind::S64,
129             Self::U64(_) => WasmTypeKind::U64,
130             Self::Float32(_) => WasmTypeKind::F32,
131             Self::Float64(_) => WasmTypeKind::F64,
132             Self::Char(_) => WasmTypeKind::Char,
133             Self::String(_) => WasmTypeKind::String,
134             Self::List(_) => WasmTypeKind::List,
135             Self::Record(_) => WasmTypeKind::Record,
136             Self::Tuple(_) => WasmTypeKind::Tuple,
137             Self::Variant(..) => WasmTypeKind::Variant,
138             Self::Enum(_) => WasmTypeKind::Enum,
139             Self::Option(_) => WasmTypeKind::Option,
140             Self::Result(_) => WasmTypeKind::Result,
141             Self::Flags(_) => WasmTypeKind::Flags,
142             Self::Resource(_)
143             | Self::Stream(_)
144             | Self::Future(_)
145             | Self::ErrorContext(_)
146             | Self::Map(_) => WasmTypeKind::Unsupported,
147         }
148     }
149 
150     impl_primitives!(
151         Self,
152         (Bool, bool, make_bool, unwrap_bool),
153         (S8, i8, make_s8, unwrap_s8),
154         (S16, i16, make_s16, unwrap_s16),
155         (S32, i32, make_s32, unwrap_s32),
156         (S64, i64, make_s64, unwrap_s64),
157         (U8, u8, make_u8, unwrap_u8),
158         (U16, u16, make_u16, unwrap_u16),
159         (U32, u32, make_u32, unwrap_u32),
160         (U64, u64, make_u64, unwrap_u64),
161         (Char, char, make_char, unwrap_char)
162     );
163 
make_f32(val: f32) -> Self164     fn make_f32(val: f32) -> Self {
165         let val = canonicalize_nan32(val);
166         Self::Float32(val)
167     }
make_f64(val: f64) -> Self168     fn make_f64(val: f64) -> Self {
169         let val = canonicalize_nan64(val);
170         Self::Float64(val)
171     }
make_string(val: Cow<str>) -> Self172     fn make_string(val: Cow<str>) -> Self {
173         Self::String(val.into())
174     }
make_list( ty: &Self::Type, vals: impl IntoIterator<Item = Self>, ) -> Result<Self, WasmValueError>175     fn make_list(
176         ty: &Self::Type,
177         vals: impl IntoIterator<Item = Self>,
178     ) -> Result<Self, WasmValueError> {
179         ensure_type_kind(ty, WasmTypeKind::List)?;
180         let val = Self::List(vals.into_iter().collect());
181         ensure_type_val(ty, &val)?;
182         Ok(val)
183     }
make_record<'a>( ty: &Self::Type, fields: impl IntoIterator<Item = (&'a str, Self)>, ) -> Result<Self, WasmValueError>184     fn make_record<'a>(
185         ty: &Self::Type,
186         fields: impl IntoIterator<Item = (&'a str, Self)>,
187     ) -> Result<Self, WasmValueError> {
188         ensure_type_kind(ty, WasmTypeKind::Record)?;
189         let values: Vec<(String, Self)> = fields
190             .into_iter()
191             .map(|(name, val)| (name.to_string(), val))
192             .collect();
193         let val = Self::Record(values);
194         ensure_type_val(ty, &val)?;
195         Ok(val)
196     }
make_tuple( ty: &Self::Type, vals: impl IntoIterator<Item = Self>, ) -> Result<Self, WasmValueError>197     fn make_tuple(
198         ty: &Self::Type,
199         vals: impl IntoIterator<Item = Self>,
200     ) -> Result<Self, WasmValueError> {
201         ensure_type_kind(ty, WasmTypeKind::Tuple)?;
202         let val = Self::Tuple(vals.into_iter().collect());
203         ensure_type_val(ty, &val)?;
204         Ok(val)
205     }
make_variant( ty: &Self::Type, case: &str, val: Option<Self>, ) -> Result<Self, WasmValueError>206     fn make_variant(
207         ty: &Self::Type,
208         case: &str,
209         val: Option<Self>,
210     ) -> Result<Self, WasmValueError> {
211         ensure_type_kind(ty, WasmTypeKind::Variant)?;
212         let val = Self::Variant(case.to_string(), val.map(Box::new));
213         ensure_type_val(ty, &val)?;
214         Ok(val)
215     }
make_enum(ty: &Self::Type, case: &str) -> Result<Self, WasmValueError>216     fn make_enum(ty: &Self::Type, case: &str) -> Result<Self, WasmValueError> {
217         ensure_type_kind(ty, WasmTypeKind::Enum)?;
218         let val = Self::Enum(case.to_string());
219         ensure_type_val(ty, &val)?;
220         Ok(val)
221     }
make_option(ty: &Self::Type, val: Option<Self>) -> Result<Self, WasmValueError>222     fn make_option(ty: &Self::Type, val: Option<Self>) -> Result<Self, WasmValueError> {
223         ensure_type_kind(ty, WasmTypeKind::Option)?;
224         let val = Self::Option(val.map(Box::new));
225         ensure_type_val(ty, &val)?;
226         Ok(val)
227     }
make_result( ty: &Self::Type, val: Result<Option<Self>, Option<Self>>, ) -> Result<Self, WasmValueError>228     fn make_result(
229         ty: &Self::Type,
230         val: Result<Option<Self>, Option<Self>>,
231     ) -> Result<Self, WasmValueError> {
232         ensure_type_kind(ty, WasmTypeKind::Result)?;
233         let val = match val {
234             Ok(val) => Self::Result(Ok(val.map(Box::new))),
235             Err(val) => Self::Result(Err(val.map(Box::new))),
236         };
237         ensure_type_val(ty, &val)?;
238         Ok(val)
239     }
make_flags<'a>( ty: &Self::Type, names: impl IntoIterator<Item = &'a str>, ) -> Result<Self, WasmValueError>240     fn make_flags<'a>(
241         ty: &Self::Type,
242         names: impl IntoIterator<Item = &'a str>,
243     ) -> Result<Self, WasmValueError> {
244         ensure_type_kind(ty, WasmTypeKind::Flags)?;
245         let val = Self::Flags(names.into_iter().map(|n| n.to_string()).collect());
246         ensure_type_val(ty, &val)?;
247         Ok(val)
248     }
249 
unwrap_f32(&self) -> f32250     fn unwrap_f32(&self) -> f32 {
251         let val = *unwrap_val!(self, Self::Float32, "f32");
252         canonicalize_nan32(val)
253     }
unwrap_f64(&self) -> f64254     fn unwrap_f64(&self) -> f64 {
255         let val = *unwrap_val!(self, Self::Float64, "f64");
256         canonicalize_nan64(val)
257     }
unwrap_string(&self) -> Cow<'_, str>258     fn unwrap_string(&self) -> Cow<'_, str> {
259         unwrap_val!(self, Self::String, "string").into()
260     }
unwrap_list(&self) -> Box<dyn Iterator<Item = Cow<'_, Self>> + '_>261     fn unwrap_list(&self) -> Box<dyn Iterator<Item = Cow<'_, Self>> + '_> {
262         let list = unwrap_val!(self, Self::List, "list");
263         Box::new(list.iter().map(cow))
264     }
unwrap_record(&self) -> Box<dyn Iterator<Item = (Cow<'_, str>, Cow<'_, Self>)> + '_>265     fn unwrap_record(&self) -> Box<dyn Iterator<Item = (Cow<'_, str>, Cow<'_, Self>)> + '_> {
266         let record = unwrap_val!(self, Self::Record, "record");
267         Box::new(record.iter().map(|(name, val)| (name.into(), cow(val))))
268     }
unwrap_tuple(&self) -> Box<dyn Iterator<Item = Cow<'_, Self>> + '_>269     fn unwrap_tuple(&self) -> Box<dyn Iterator<Item = Cow<'_, Self>> + '_> {
270         let tuple = unwrap_val!(self, Self::Tuple, "tuple");
271         Box::new(tuple.iter().map(cow))
272     }
unwrap_variant(&self) -> (Cow<'_, str>, Option<Cow<'_, Self>>)273     fn unwrap_variant(&self) -> (Cow<'_, str>, Option<Cow<'_, Self>>) {
274         let (discriminant, payload) = unwrap_2val!(self, Self::Variant, "variant");
275         (discriminant.into(), payload.as_deref().map(cow))
276     }
unwrap_enum(&self) -> Cow<'_, str>277     fn unwrap_enum(&self) -> Cow<'_, str> {
278         unwrap_val!(self, Self::Enum, "enum").into()
279     }
unwrap_option(&self) -> Option<Cow<'_, Self>>280     fn unwrap_option(&self) -> Option<Cow<'_, Self>> {
281         unwrap_val!(self, Self::Option, "option")
282             .as_deref()
283             .map(cow)
284     }
unwrap_result(&self) -> Result<Option<Cow<'_, Self>>, Option<Cow<'_, Self>>>285     fn unwrap_result(&self) -> Result<Option<Cow<'_, Self>>, Option<Cow<'_, Self>>> {
286         match unwrap_val!(self, Self::Result, "result") {
287             Ok(t) => Ok(t.as_deref().map(cow)),
288             Err(e) => Err(e.as_deref().map(cow)),
289         }
290     }
unwrap_flags(&self) -> Box<dyn Iterator<Item = Cow<'_, str>> + '_>291     fn unwrap_flags(&self) -> Box<dyn Iterator<Item = Cow<'_, str>> + '_> {
292         let flags = unwrap_val!(self, Self::Flags, "flags");
293         Box::new(flags.iter().map(Into::into))
294     }
295 }
296 
297 // Returns an error if the given component::Val is not of the given component::Type.
298 //
299 // The component::Val::Resource(_) variant results in an unsupported error at this time.
ensure_type_val(ty: &component::Type, val: &component::Val) -> Result<(), WasmValueError>300 fn ensure_type_val(ty: &component::Type, val: &component::Val) -> Result<(), WasmValueError> {
301     let wrong_value_type = || -> Result<(), WasmValueError> {
302         Err(WasmValueError::WrongValueType {
303             ty: wasm_wave::wasm::DisplayType(ty).to_string(),
304             val: wasm_wave::wasm::DisplayValue(val).to_string(),
305         })
306     };
307 
308     if ty.kind() != val.kind() {
309         return wrong_value_type();
310     }
311 
312     match val {
313         component::Val::List(vals) => {
314             let list_type = ty.unwrap_list().ty();
315             for val in vals {
316                 ensure_type_val(&list_type, val)?;
317             }
318         }
319         component::Val::Record(vals) => {
320             let record_handle = ty.unwrap_record();
321             // Check that every non option field type is found in the Vec
322             for field in record_handle.fields() {
323                 if !matches!(field.ty, component::Type::Option(_))
324                     && !vals.iter().any(|(n, _)| n == field.name)
325                 {
326                     return wrong_value_type();
327                 }
328             }
329             // Check that every (String, Val) of the given Vec is a correct field_type
330             for (name, field_val) in vals.iter() {
331                 // N.B. The `fields` call in each iteration is non-trivial, perhaps a cleaner way
332                 // using the loop above will present itself.
333                 if let Some(field) = record_handle.fields().find(|field| field.name == name) {
334                     ensure_type_val(&field.ty, field_val)?;
335                 } else {
336                     return wrong_value_type();
337                 }
338             }
339         }
340         component::Val::Tuple(vals) => {
341             let field_types = ty.unwrap_tuple().types();
342             if field_types.len() != vals.len() {
343                 return wrong_value_type();
344             }
345             for (ty, val) in field_types.into_iter().zip(vals.iter()) {
346                 ensure_type_val(&ty, val)?;
347             }
348         }
349         component::Val::Variant(name, optional_payload) => {
350             if let Some(case) = ty.unwrap_variant().cases().find(|case| case.name == name) {
351                 match (optional_payload, case.ty) {
352                     (None, None) => {}
353                     (Some(payload), Some(payload_ty)) => ensure_type_val(&payload_ty, payload)?,
354                     _ => return wrong_value_type(),
355                 }
356             } else {
357                 return wrong_value_type();
358             }
359         }
360         component::Val::Enum(name) => {
361             if !ty.unwrap_enum().names().any(|n| n == name) {
362                 return wrong_value_type();
363             }
364         }
365         component::Val::Option(Some(some_val)) => {
366             ensure_type_val(&ty.unwrap_option().ty(), some_val.as_ref())?;
367         }
368         component::Val::Result(res_val) => {
369             let result_handle = ty.unwrap_result();
370             match res_val {
371                 Ok(ok) => match (ok, result_handle.ok()) {
372                     (None, None) => {}
373                     (Some(ok_val), Some(ok_ty)) => ensure_type_val(&ok_ty, ok_val.as_ref())?,
374                     _ => return wrong_value_type(),
375                 },
376                 Err(err) => match (err, result_handle.err()) {
377                     (None, None) => {}
378                     (Some(err_val), Some(err_ty)) => ensure_type_val(&err_ty, err_val.as_ref())?,
379                     _ => return wrong_value_type(),
380                 },
381             }
382         }
383         component::Val::Flags(flags) => {
384             let flags_handle = ty.unwrap_flags();
385             for flag in flags {
386                 if !flags_handle.names().any(|n| n == flag) {
387                     return wrong_value_type();
388                 }
389             }
390         }
391         component::Val::Resource(_) => {
392             return Err(WasmValueError::UnsupportedType(
393                 DisplayValue(val).to_string(),
394             ));
395         }
396 
397         // Any leaf variant type has already had its kind compared above; nothing further to check.
398         // Likewise, the component::Option(None) arm would have nothing left to check.
399         _ => {}
400     }
401     Ok(())
402 }
403 
404 impl WasmFunc for component::types::ComponentFunc {
405     type Type = component::Type;
406 
params(&self) -> Box<dyn Iterator<Item = Self::Type> + '_>407     fn params(&self) -> Box<dyn Iterator<Item = Self::Type> + '_> {
408         Box::new(self.params().map(|(_n, t)| t))
409     }
410 
results(&self) -> Box<dyn Iterator<Item = Self::Type> + '_>411     fn results(&self) -> Box<dyn Iterator<Item = Self::Type> + '_> {
412         Box::new(self.results())
413     }
414 }
415 
cow<T: Clone>(t: &T) -> Cow<'_, T>416 fn cow<T: Clone>(t: &T) -> Cow<'_, T> {
417     Cow::Borrowed(t)
418 }
419 
420 #[cfg(test)]
421 mod tests {
422     #[test]
component_vals_smoke_test()423     fn component_vals_smoke_test() {
424         use crate::component::Val;
425         for (val, want) in [
426             (Val::Bool(false), "false"),
427             (Val::Bool(true), "true"),
428             (Val::S8(10), "10"),
429             (Val::S16(-10), "-10"),
430             (Val::S32(1_000_000), "1000000"),
431             (Val::S64(0), "0"),
432             (Val::U8(255), "255"),
433             (Val::U16(0), "0"),
434             (Val::U32(1_000_000), "1000000"),
435             (Val::U64(9), "9"),
436             (Val::Float32(1.5), "1.5"),
437             (Val::Float32(f32::NAN), "nan"),
438             (Val::Float32(f32::INFINITY), "inf"),
439             (Val::Float32(f32::NEG_INFINITY), "-inf"),
440             (Val::Float64(-1.5e-10), "-0.00000000015"),
441             (Val::Float64(f64::NAN), "nan"),
442             (Val::Float64(f64::INFINITY), "inf"),
443             (Val::Float64(f64::NEG_INFINITY), "-inf"),
444             (Val::Char('x'), "'x'"),
445             (Val::Char('☃'), "'☃'"),
446             (Val::Char('\''), r"'\''"),
447             (Val::Char('\0'), r"'\u{0}'"),
448             (Val::Char('\x1b'), r"'\u{1b}'"),
449             (Val::Char('��'), r"'��'"),
450             (Val::String("abc".into()), r#""abc""#),
451             (Val::String(r#"\☃""#.into()), r#""\\☃\"""#),
452             (Val::String("\t\r\n\0".into()), r#""\t\r\n\u{0}""#),
453         ] {
454             let got = wasm_wave::to_string(&val)
455                 .unwrap_or_else(|err| panic!("failed to serialize {val:?}: {err}"));
456             assert_eq!(got, want, "for {val:?}");
457         }
458     }
459 
460     #[test]
test_round_trip_floats()461     fn test_round_trip_floats() {
462         use crate::component::{Type, Val};
463         use std::fmt::Debug;
464 
465         fn round_trip<V: wasm_wave::wasm::WasmValue + PartialEq + Debug>(ty: &V::Type, val: &V) {
466             let val_str = wasm_wave::to_string(val).unwrap();
467             let result: V = wasm_wave::from_str::<V>(ty, &val_str).unwrap();
468             assert_eq!(val, &result);
469         }
470 
471         for i in 0..100 {
472             for j in 0..100 {
473                 round_trip(&Type::Float32, &Val::Float32(i as f32 / j as f32));
474                 round_trip(&Type::Float64, &Val::Float64(i as f64 / j as f64));
475             }
476         }
477 
478         round_trip(&Type::Float32, &Val::Float32(f32::EPSILON));
479         round_trip(&Type::Float64, &Val::Float64(f64::EPSILON));
480     }
481 }
482