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 49 | Self::Map(_) => WasmTypeKind::Unsupported, 50 } 51 } 52 53 fn list_element_type(&self) -> Option<Self> { 54 Some(maybe_unwrap_type!(self, Self::List)?.ty()) 55 } 56 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 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 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 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 85 fn option_some_type(&self) -> Option<Self> { 86 maybe_unwrap_type!(self, Self::Option).map(|o| o.ty()) 87 } 88 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 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 119 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 164 fn make_f32(val: f32) -> Self { 165 let val = canonicalize_nan32(val); 166 Self::Float32(val) 167 } 168 fn make_f64(val: f64) -> Self { 169 let val = canonicalize_nan64(val); 170 Self::Float64(val) 171 } 172 fn make_string(val: Cow<str>) -> Self { 173 Self::String(val.into()) 174 } 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 } 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 } 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 } 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 } 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 } 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 } 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 } 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 250 fn unwrap_f32(&self) -> f32 { 251 let val = *unwrap_val!(self, Self::Float32, "f32"); 252 canonicalize_nan32(val) 253 } 254 fn unwrap_f64(&self) -> f64 { 255 let val = *unwrap_val!(self, Self::Float64, "f64"); 256 canonicalize_nan64(val) 257 } 258 fn unwrap_string(&self) -> Cow<'_, str> { 259 unwrap_val!(self, Self::String, "string").into() 260 } 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 } 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 } 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 } 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 } 277 fn unwrap_enum(&self) -> Cow<'_, str> { 278 unwrap_val!(self, Self::Enum, "enum").into() 279 } 280 fn unwrap_option(&self) -> Option<Cow<'_, Self>> { 281 unwrap_val!(self, Self::Option, "option") 282 .as_deref() 283 .map(cow) 284 } 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 } 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. 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 407 fn params(&self) -> Box<dyn Iterator<Item = Self::Type> + '_> { 408 Box::new(self.params().map(|(_n, t)| t)) 409 } 410 411 fn results(&self) -> Box<dyn Iterator<Item = Self::Type> + '_> { 412 Box::new(self.results()) 413 } 414 } 415 416 fn cow<T: Clone>(t: &T) -> Cow<'_, T> { 417 Cow::Borrowed(t) 418 } 419 420 #[cfg(test)] 421 mod tests { 422 #[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] 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