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