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