1 use crate::ValRaw; 2 use crate::component::ResourceAny; 3 use crate::component::concurrent::{self, ErrorContext, HostFuture, HostStream}; 4 use crate::component::func::{Lift, LiftContext, Lower, LowerContext, desc}; 5 use crate::prelude::*; 6 use core::mem::MaybeUninit; 7 use core::slice::{Iter, IterMut}; 8 use wasmtime_component_util::{DiscriminantSize, FlagsSize}; 9 use wasmtime_environ::component::{ 10 CanonicalAbiInfo, InterfaceType, TypeEnum, TypeFlags, TypeListIndex, TypeOption, TypeResult, 11 TypeVariant, VariantInfo, 12 }; 13 14 /// Represents possible runtime values which a component function can either 15 /// consume or produce 16 /// 17 /// This is a dynamic representation of possible values in the component model. 18 /// Note that this is not an efficient representation but is instead intended to 19 /// be a flexible and somewhat convenient representation. The most efficient 20 /// representation of component model types is to use the `bindgen!` macro to 21 /// generate native Rust types with specialized liftings and lowerings. 22 /// 23 /// This type is used in conjunction with [`Func::call`] for example if the 24 /// signature of a component is not statically known ahead of time. 25 /// 26 /// # Equality and `Val` 27 /// 28 /// This type implements both the Rust `PartialEq` and `Eq` traits. This type 29 /// additionally contains values which are not necessarily easily equated, 30 /// however, such as floats (`Float32` and `Float64`) and resources. Equality 31 /// does require that two values have the same type, and then these cases are 32 /// handled as: 33 /// 34 /// * Floats are tested if they are "semantically the same" meaning all NaN 35 /// values are equal to all other NaN values. Additionally zero values must be 36 /// exactly the same, so positive zero is not equal to negative zero. The 37 /// primary use case at this time is fuzzing-related equality which this is 38 /// sufficient for. 39 /// 40 /// * Resources are tested if their types and indices into the host table are 41 /// equal. This does not compare the underlying representation so borrows of 42 /// the same guest resource are not considered equal. This additionally 43 /// doesn't go further and test for equality in the guest itself (for example 44 /// two different heap allocations of `Box<u32>` can be equal in normal Rust 45 /// if they contain the same value, but will never be considered equal when 46 /// compared as `Val::Resource`s). 47 /// 48 /// In general if a strict guarantee about equality is required here it's 49 /// recommended to "build your own" as this equality intended for fuzzing 50 /// Wasmtime may not be suitable for you. 51 /// 52 /// # Component model types and `Val` 53 /// 54 /// The `Val` type here does not contain enough information to say what the 55 /// component model type of a `Val` is. This is instead more of an AST of sorts. 56 /// For example the `Val::Enum` only carries information about a single 57 /// discriminant, not the entire enumeration or what it's a discriminant of. 58 /// 59 /// This means that when a `Val` is passed to Wasmtime, for example as a 60 /// function parameter when calling a function or as a return value from an 61 /// host-defined imported function, then it must pass a type-check. Instances of 62 /// `Val` are type-checked against what's required by the component itself. 63 /// 64 /// [`Func::call`]: crate::component::Func::call 65 #[derive(Debug, Clone)] 66 #[expect(missing_docs, reason = "self-describing variants")] 67 pub enum Val { 68 Bool(bool), 69 S8(i8), 70 U8(u8), 71 S16(i16), 72 U16(u16), 73 S32(i32), 74 U32(u32), 75 S64(i64), 76 U64(u64), 77 Float32(f32), 78 Float64(f64), 79 Char(char), 80 String(String), 81 List(Vec<Val>), 82 Record(Vec<(String, Val)>), 83 Tuple(Vec<Val>), 84 Variant(String, Option<Box<Val>>), 85 Enum(String), 86 Option(Option<Box<Val>>), 87 Result(Result<Option<Box<Val>>, Option<Box<Val>>>), 88 Flags(Vec<String>), 89 Resource(ResourceAny), 90 Future(FutureAny), 91 Stream(StreamAny), 92 ErrorContext(ErrorContextAny), 93 } 94 95 impl Val { 96 /// Deserialize a value of this type from core Wasm stack values. 97 pub(crate) fn lift( 98 cx: &mut LiftContext<'_>, 99 ty: InterfaceType, 100 src: &mut Iter<'_, ValRaw>, 101 ) -> Result<Val> { 102 Ok(match ty { 103 InterfaceType::Bool => Val::Bool(bool::linear_lift_from_flat(cx, ty, next(src))?), 104 InterfaceType::S8 => Val::S8(i8::linear_lift_from_flat(cx, ty, next(src))?), 105 InterfaceType::U8 => Val::U8(u8::linear_lift_from_flat(cx, ty, next(src))?), 106 InterfaceType::S16 => Val::S16(i16::linear_lift_from_flat(cx, ty, next(src))?), 107 InterfaceType::U16 => Val::U16(u16::linear_lift_from_flat(cx, ty, next(src))?), 108 InterfaceType::S32 => Val::S32(i32::linear_lift_from_flat(cx, ty, next(src))?), 109 InterfaceType::U32 => Val::U32(u32::linear_lift_from_flat(cx, ty, next(src))?), 110 InterfaceType::S64 => Val::S64(i64::linear_lift_from_flat(cx, ty, next(src))?), 111 InterfaceType::U64 => Val::U64(u64::linear_lift_from_flat(cx, ty, next(src))?), 112 InterfaceType::Float32 => Val::Float32(f32::linear_lift_from_flat(cx, ty, next(src))?), 113 InterfaceType::Float64 => Val::Float64(f64::linear_lift_from_flat(cx, ty, next(src))?), 114 InterfaceType::Char => Val::Char(char::linear_lift_from_flat(cx, ty, next(src))?), 115 InterfaceType::Own(_) | InterfaceType::Borrow(_) => { 116 Val::Resource(ResourceAny::linear_lift_from_flat(cx, ty, next(src))?) 117 } 118 InterfaceType::String => Val::String(<_>::linear_lift_from_flat( 119 cx, 120 ty, 121 &[*next(src), *next(src)], 122 )?), 123 InterfaceType::List(i) => { 124 // FIXME(#4311): needs memory64 treatment 125 let ptr = u32::linear_lift_from_flat(cx, InterfaceType::U32, next(src))? as usize; 126 let len = u32::linear_lift_from_flat(cx, InterfaceType::U32, next(src))? as usize; 127 load_list(cx, i, ptr, len)? 128 } 129 InterfaceType::Record(i) => Val::Record( 130 cx.types[i] 131 .fields 132 .iter() 133 .map(|field| { 134 let val = Self::lift(cx, field.ty, src)?; 135 Ok((field.name.to_string(), val)) 136 }) 137 .collect::<Result<_>>()?, 138 ), 139 InterfaceType::Tuple(i) => Val::Tuple( 140 cx.types[i] 141 .types 142 .iter() 143 .map(|ty| Self::lift(cx, *ty, src)) 144 .collect::<Result<_>>()?, 145 ), 146 InterfaceType::Variant(i) => { 147 let vty = &cx.types[i]; 148 let (discriminant, value) = lift_variant( 149 cx, 150 cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(), 151 vty.cases.values().copied(), 152 src, 153 )?; 154 155 let (k, _) = vty.cases.get_index(discriminant as usize).unwrap(); 156 Val::Variant(k.clone(), value) 157 } 158 InterfaceType::Enum(i) => { 159 let ety = &cx.types[i]; 160 let (discriminant, _) = lift_variant( 161 cx, 162 cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(), 163 ety.names.iter().map(|_| None), 164 src, 165 )?; 166 167 Val::Enum(ety.names[discriminant as usize].clone()) 168 } 169 InterfaceType::Option(i) => { 170 let (_discriminant, value) = lift_variant( 171 cx, 172 cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(), 173 [None, Some(cx.types[i].ty)].into_iter(), 174 src, 175 )?; 176 177 Val::Option(value) 178 } 179 InterfaceType::Result(i) => { 180 let result_ty = &cx.types[i]; 181 let (discriminant, value) = lift_variant( 182 cx, 183 cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(), 184 [result_ty.ok, result_ty.err].into_iter(), 185 src, 186 )?; 187 188 Val::Result(if discriminant == 0 { 189 Ok(value) 190 } else { 191 Err(value) 192 }) 193 } 194 InterfaceType::Flags(i) => { 195 let u32_count = cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(); 196 let ty = &cx.types[i]; 197 let mut flags = Vec::new(); 198 for i in 0..u32::try_from(u32_count).unwrap() { 199 push_flags( 200 ty, 201 &mut flags, 202 i * 32, 203 u32::linear_lift_from_flat(cx, InterfaceType::U32, next(src))?, 204 ); 205 } 206 207 Val::Flags(flags) 208 } 209 InterfaceType::Future(_) => { 210 HostFuture::<()>::linear_lift_from_flat(cx, ty, next(src))?.into_val() 211 } 212 InterfaceType::Stream(_) => { 213 HostStream::<()>::linear_lift_from_flat(cx, ty, next(src))?.into_val() 214 } 215 InterfaceType::ErrorContext(_) => { 216 ErrorContext::linear_lift_from_flat(cx, ty, next(src))?.into_val() 217 } 218 }) 219 } 220 221 /// Deserialize a value of this type from the heap. 222 pub(crate) fn load(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Val> { 223 Ok(match ty { 224 InterfaceType::Bool => Val::Bool(bool::linear_lift_from_memory(cx, ty, bytes)?), 225 InterfaceType::S8 => Val::S8(i8::linear_lift_from_memory(cx, ty, bytes)?), 226 InterfaceType::U8 => Val::U8(u8::linear_lift_from_memory(cx, ty, bytes)?), 227 InterfaceType::S16 => Val::S16(i16::linear_lift_from_memory(cx, ty, bytes)?), 228 InterfaceType::U16 => Val::U16(u16::linear_lift_from_memory(cx, ty, bytes)?), 229 InterfaceType::S32 => Val::S32(i32::linear_lift_from_memory(cx, ty, bytes)?), 230 InterfaceType::U32 => Val::U32(u32::linear_lift_from_memory(cx, ty, bytes)?), 231 InterfaceType::S64 => Val::S64(i64::linear_lift_from_memory(cx, ty, bytes)?), 232 InterfaceType::U64 => Val::U64(u64::linear_lift_from_memory(cx, ty, bytes)?), 233 InterfaceType::Float32 => Val::Float32(f32::linear_lift_from_memory(cx, ty, bytes)?), 234 InterfaceType::Float64 => Val::Float64(f64::linear_lift_from_memory(cx, ty, bytes)?), 235 InterfaceType::Char => Val::Char(char::linear_lift_from_memory(cx, ty, bytes)?), 236 InterfaceType::String => Val::String(<_>::linear_lift_from_memory(cx, ty, bytes)?), 237 InterfaceType::Own(_) | InterfaceType::Borrow(_) => { 238 Val::Resource(ResourceAny::linear_lift_from_memory(cx, ty, bytes)?) 239 } 240 InterfaceType::List(i) => { 241 // FIXME(#4311): needs memory64 treatment 242 let ptr = u32::from_le_bytes(bytes[..4].try_into().unwrap()) as usize; 243 let len = u32::from_le_bytes(bytes[4..].try_into().unwrap()) as usize; 244 load_list(cx, i, ptr, len)? 245 } 246 247 InterfaceType::Record(i) => { 248 let mut offset = 0; 249 let fields = cx.types[i].fields.iter(); 250 Val::Record( 251 fields 252 .map(|field| -> Result<(String, Val)> { 253 let abi = cx.types.canonical_abi(&field.ty); 254 let offset = abi.next_field32(&mut offset); 255 let offset = usize::try_from(offset).unwrap(); 256 let size = usize::try_from(abi.size32).unwrap(); 257 Ok(( 258 field.name.to_string(), 259 Val::load(cx, field.ty, &bytes[offset..][..size])?, 260 )) 261 }) 262 .collect::<Result<_>>()?, 263 ) 264 } 265 InterfaceType::Tuple(i) => { 266 let types = cx.types[i].types.iter().copied(); 267 let mut offset = 0; 268 Val::Tuple( 269 types 270 .map(|ty| { 271 let abi = cx.types.canonical_abi(&ty); 272 let offset = abi.next_field32(&mut offset); 273 let offset = usize::try_from(offset).unwrap(); 274 let size = usize::try_from(abi.size32).unwrap(); 275 Val::load(cx, ty, &bytes[offset..][..size]) 276 }) 277 .collect::<Result<_>>()?, 278 ) 279 } 280 InterfaceType::Variant(i) => { 281 let ty = &cx.types[i]; 282 let (discriminant, value) = 283 load_variant(cx, &ty.info, ty.cases.values().copied(), bytes)?; 284 285 let (k, _) = ty.cases.get_index(discriminant as usize).unwrap(); 286 Val::Variant(k.clone(), value) 287 } 288 InterfaceType::Enum(i) => { 289 let ty = &cx.types[i]; 290 let (discriminant, _) = 291 load_variant(cx, &ty.info, ty.names.iter().map(|_| None), bytes)?; 292 293 Val::Enum(ty.names[discriminant as usize].clone()) 294 } 295 InterfaceType::Option(i) => { 296 let ty = &cx.types[i]; 297 let (_discriminant, value) = 298 load_variant(cx, &ty.info, [None, Some(ty.ty)].into_iter(), bytes)?; 299 300 Val::Option(value) 301 } 302 InterfaceType::Result(i) => { 303 let ty = &cx.types[i]; 304 let (discriminant, value) = 305 load_variant(cx, &ty.info, [ty.ok, ty.err].into_iter(), bytes)?; 306 307 Val::Result(if discriminant == 0 { 308 Ok(value) 309 } else { 310 Err(value) 311 }) 312 } 313 InterfaceType::Flags(i) => { 314 let ty = &cx.types[i]; 315 let mut flags = Vec::new(); 316 match FlagsSize::from_count(ty.names.len()) { 317 FlagsSize::Size0 => {} 318 FlagsSize::Size1 => { 319 let bits = u8::linear_lift_from_memory(cx, InterfaceType::U8, bytes)?; 320 push_flags(ty, &mut flags, 0, u32::from(bits)); 321 } 322 FlagsSize::Size2 => { 323 let bits = u16::linear_lift_from_memory(cx, InterfaceType::U16, bytes)?; 324 push_flags(ty, &mut flags, 0, u32::from(bits)); 325 } 326 FlagsSize::Size4Plus(n) => { 327 for i in 0..n { 328 let bits = u32::linear_lift_from_memory( 329 cx, 330 InterfaceType::U32, 331 &bytes[usize::from(i) * 4..][..4], 332 )?; 333 push_flags(ty, &mut flags, u32::from(i) * 32, bits); 334 } 335 } 336 } 337 Val::Flags(flags) 338 } 339 InterfaceType::Future(_) => { 340 HostFuture::<()>::linear_lift_from_memory(cx, ty, bytes)?.into_val() 341 } 342 InterfaceType::Stream(_) => { 343 HostStream::<()>::linear_lift_from_memory(cx, ty, bytes)?.into_val() 344 } 345 InterfaceType::ErrorContext(_) => { 346 ErrorContext::linear_lift_from_memory(cx, ty, bytes)?.into_val() 347 } 348 }) 349 } 350 351 /// Serialize this value as core Wasm stack values. 352 pub(crate) fn lower<T>( 353 &self, 354 cx: &mut LowerContext<'_, T>, 355 ty: InterfaceType, 356 dst: &mut IterMut<'_, MaybeUninit<ValRaw>>, 357 ) -> Result<()> { 358 match (ty, self) { 359 (InterfaceType::Bool, Val::Bool(value)) => { 360 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 361 } 362 (InterfaceType::Bool, _) => unexpected(ty, self), 363 (InterfaceType::S8, Val::S8(value)) => { 364 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 365 } 366 (InterfaceType::S8, _) => unexpected(ty, self), 367 (InterfaceType::U8, Val::U8(value)) => { 368 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 369 } 370 (InterfaceType::U8, _) => unexpected(ty, self), 371 (InterfaceType::S16, Val::S16(value)) => { 372 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 373 } 374 (InterfaceType::S16, _) => unexpected(ty, self), 375 (InterfaceType::U16, Val::U16(value)) => { 376 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 377 } 378 (InterfaceType::U16, _) => unexpected(ty, self), 379 (InterfaceType::S32, Val::S32(value)) => { 380 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 381 } 382 (InterfaceType::S32, _) => unexpected(ty, self), 383 (InterfaceType::U32, Val::U32(value)) => { 384 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 385 } 386 (InterfaceType::U32, _) => unexpected(ty, self), 387 (InterfaceType::S64, Val::S64(value)) => { 388 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 389 } 390 (InterfaceType::S64, _) => unexpected(ty, self), 391 (InterfaceType::U64, Val::U64(value)) => { 392 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 393 } 394 (InterfaceType::U64, _) => unexpected(ty, self), 395 (InterfaceType::Float32, Val::Float32(value)) => { 396 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 397 } 398 (InterfaceType::Float32, _) => unexpected(ty, self), 399 (InterfaceType::Float64, Val::Float64(value)) => { 400 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 401 } 402 (InterfaceType::Float64, _) => unexpected(ty, self), 403 (InterfaceType::Char, Val::Char(value)) => { 404 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 405 } 406 (InterfaceType::Char, _) => unexpected(ty, self), 407 // NB: `lower` on `ResourceAny` does its own type-checking, so skip 408 // looking at it here. 409 (InterfaceType::Borrow(_) | InterfaceType::Own(_), Val::Resource(value)) => { 410 value.linear_lower_to_flat(cx, ty, next_mut(dst)) 411 } 412 (InterfaceType::Borrow(_) | InterfaceType::Own(_), _) => unexpected(ty, self), 413 (InterfaceType::String, Val::String(value)) => { 414 let my_dst = &mut MaybeUninit::<[ValRaw; 2]>::uninit(); 415 value.linear_lower_to_flat(cx, ty, my_dst)?; 416 let my_dst = unsafe { my_dst.assume_init() }; 417 next_mut(dst).write(my_dst[0]); 418 next_mut(dst).write(my_dst[1]); 419 Ok(()) 420 } 421 (InterfaceType::String, _) => unexpected(ty, self), 422 (InterfaceType::List(ty), Val::List(values)) => { 423 let ty = &cx.types[ty]; 424 let (ptr, len) = lower_list(cx, ty.element, values)?; 425 next_mut(dst).write(ValRaw::i64(ptr as i64)); 426 next_mut(dst).write(ValRaw::i64(len as i64)); 427 Ok(()) 428 } 429 (InterfaceType::List(_), _) => unexpected(ty, self), 430 (InterfaceType::Record(ty), Val::Record(values)) => { 431 let ty = &cx.types[ty]; 432 if ty.fields.len() != values.len() { 433 bail!("expected {} fields, got {}", ty.fields.len(), values.len()); 434 } 435 for ((name, value), field) in values.iter().zip(ty.fields.iter()) { 436 if *name != field.name { 437 bail!("expected field `{}`, got `{name}`", field.name); 438 } 439 value.lower(cx, field.ty, dst)?; 440 } 441 Ok(()) 442 } 443 (InterfaceType::Record(_), _) => unexpected(ty, self), 444 (InterfaceType::Tuple(ty), Val::Tuple(values)) => { 445 let ty = &cx.types[ty]; 446 if ty.types.len() != values.len() { 447 bail!("expected {} types, got {}", ty.types.len(), values.len()); 448 } 449 for (value, ty) in values.iter().zip(ty.types.iter()) { 450 value.lower(cx, *ty, dst)?; 451 } 452 Ok(()) 453 } 454 (InterfaceType::Tuple(_), _) => unexpected(ty, self), 455 (InterfaceType::Variant(ty), Val::Variant(n, v)) => { 456 GenericVariant::variant(&cx.types[ty], n, v)?.lower(cx, dst) 457 } 458 (InterfaceType::Variant(_), _) => unexpected(ty, self), 459 (InterfaceType::Option(ty), Val::Option(v)) => { 460 GenericVariant::option(&cx.types[ty], v).lower(cx, dst) 461 } 462 (InterfaceType::Option(_), _) => unexpected(ty, self), 463 (InterfaceType::Result(ty), Val::Result(v)) => { 464 GenericVariant::result(&cx.types[ty], v)?.lower(cx, dst) 465 } 466 (InterfaceType::Result(_), _) => unexpected(ty, self), 467 (InterfaceType::Enum(ty), Val::Enum(discriminant)) => { 468 let discriminant = get_enum_discriminant(&cx.types[ty], discriminant)?; 469 next_mut(dst).write(ValRaw::u32(discriminant)); 470 Ok(()) 471 } 472 (InterfaceType::Enum(_), _) => unexpected(ty, self), 473 (InterfaceType::Flags(ty), Val::Flags(value)) => { 474 let ty = &cx.types[ty]; 475 let storage = flags_to_storage(ty, value)?; 476 for value in storage { 477 next_mut(dst).write(ValRaw::u32(value)); 478 } 479 Ok(()) 480 } 481 (InterfaceType::Flags(_), _) => unexpected(ty, self), 482 (InterfaceType::Future(_), Val::Future(FutureAny(rep))) => { 483 concurrent::lower_future_to_index(*rep, cx, ty)?.linear_lower_to_flat( 484 cx, 485 InterfaceType::U32, 486 next_mut(dst), 487 ) 488 } 489 (InterfaceType::Future(_), _) => unexpected(ty, self), 490 (InterfaceType::Stream(_), Val::Stream(StreamAny(rep))) => { 491 concurrent::lower_stream_to_index(*rep, cx, ty)?.linear_lower_to_flat( 492 cx, 493 InterfaceType::U32, 494 next_mut(dst), 495 ) 496 } 497 (InterfaceType::Stream(_), _) => unexpected(ty, self), 498 (InterfaceType::ErrorContext(_), Val::ErrorContext(ErrorContextAny(rep))) => { 499 concurrent::lower_error_context_to_index(*rep, cx, ty)?.linear_lower_to_flat( 500 cx, 501 InterfaceType::U32, 502 next_mut(dst), 503 ) 504 } 505 (InterfaceType::ErrorContext(_), _) => unexpected(ty, self), 506 } 507 } 508 509 /// Serialize this value to the heap at the specified memory location. 510 pub(crate) fn store<T>( 511 &self, 512 cx: &mut LowerContext<'_, T>, 513 ty: InterfaceType, 514 offset: usize, 515 ) -> Result<()> { 516 debug_assert!(offset % usize::try_from(cx.types.canonical_abi(&ty).align32)? == 0); 517 518 match (ty, self) { 519 (InterfaceType::Bool, Val::Bool(value)) => value.linear_lower_to_memory(cx, ty, offset), 520 (InterfaceType::Bool, _) => unexpected(ty, self), 521 (InterfaceType::U8, Val::U8(value)) => value.linear_lower_to_memory(cx, ty, offset), 522 (InterfaceType::U8, _) => unexpected(ty, self), 523 (InterfaceType::S8, Val::S8(value)) => value.linear_lower_to_memory(cx, ty, offset), 524 (InterfaceType::S8, _) => unexpected(ty, self), 525 (InterfaceType::U16, Val::U16(value)) => value.linear_lower_to_memory(cx, ty, offset), 526 (InterfaceType::U16, _) => unexpected(ty, self), 527 (InterfaceType::S16, Val::S16(value)) => value.linear_lower_to_memory(cx, ty, offset), 528 (InterfaceType::S16, _) => unexpected(ty, self), 529 (InterfaceType::U32, Val::U32(value)) => value.linear_lower_to_memory(cx, ty, offset), 530 (InterfaceType::U32, _) => unexpected(ty, self), 531 (InterfaceType::S32, Val::S32(value)) => value.linear_lower_to_memory(cx, ty, offset), 532 (InterfaceType::S32, _) => unexpected(ty, self), 533 (InterfaceType::U64, Val::U64(value)) => value.linear_lower_to_memory(cx, ty, offset), 534 (InterfaceType::U64, _) => unexpected(ty, self), 535 (InterfaceType::S64, Val::S64(value)) => value.linear_lower_to_memory(cx, ty, offset), 536 (InterfaceType::S64, _) => unexpected(ty, self), 537 (InterfaceType::Float32, Val::Float32(value)) => { 538 value.linear_lower_to_memory(cx, ty, offset) 539 } 540 (InterfaceType::Float32, _) => unexpected(ty, self), 541 (InterfaceType::Float64, Val::Float64(value)) => { 542 value.linear_lower_to_memory(cx, ty, offset) 543 } 544 (InterfaceType::Float64, _) => unexpected(ty, self), 545 (InterfaceType::Char, Val::Char(value)) => value.linear_lower_to_memory(cx, ty, offset), 546 (InterfaceType::Char, _) => unexpected(ty, self), 547 (InterfaceType::String, Val::String(value)) => { 548 value.linear_lower_to_memory(cx, ty, offset) 549 } 550 (InterfaceType::String, _) => unexpected(ty, self), 551 552 // NB: resources do type-checking when they lower. 553 (InterfaceType::Borrow(_) | InterfaceType::Own(_), Val::Resource(value)) => { 554 value.linear_lower_to_memory(cx, ty, offset) 555 } 556 (InterfaceType::Borrow(_) | InterfaceType::Own(_), _) => unexpected(ty, self), 557 (InterfaceType::List(ty), Val::List(values)) => { 558 let ty = &cx.types[ty]; 559 let (ptr, len) = lower_list(cx, ty.element, values)?; 560 // FIXME(#4311): needs memory64 handling 561 *cx.get(offset + 0) = u32::try_from(ptr).unwrap().to_le_bytes(); 562 *cx.get(offset + 4) = u32::try_from(len).unwrap().to_le_bytes(); 563 Ok(()) 564 } 565 (InterfaceType::List(_), _) => unexpected(ty, self), 566 (InterfaceType::Record(ty), Val::Record(values)) => { 567 let ty = &cx.types[ty]; 568 if ty.fields.len() != values.len() { 569 bail!("expected {} fields, got {}", ty.fields.len(), values.len()); 570 } 571 let mut offset = offset; 572 for ((name, value), field) in values.iter().zip(ty.fields.iter()) { 573 if *name != field.name { 574 bail!("expected field `{}`, got `{name}`", field.name); 575 } 576 value.store( 577 cx, 578 field.ty, 579 cx.types 580 .canonical_abi(&field.ty) 581 .next_field32_size(&mut offset), 582 )?; 583 } 584 Ok(()) 585 } 586 (InterfaceType::Record(_), _) => unexpected(ty, self), 587 (InterfaceType::Tuple(ty), Val::Tuple(values)) => { 588 let ty = &cx.types[ty]; 589 if ty.types.len() != values.len() { 590 bail!("expected {} types, got {}", ty.types.len(), values.len()); 591 } 592 let mut offset = offset; 593 for (value, ty) in values.iter().zip(ty.types.iter()) { 594 value.store( 595 cx, 596 *ty, 597 cx.types.canonical_abi(ty).next_field32_size(&mut offset), 598 )?; 599 } 600 Ok(()) 601 } 602 (InterfaceType::Tuple(_), _) => unexpected(ty, self), 603 604 (InterfaceType::Variant(ty), Val::Variant(n, v)) => { 605 GenericVariant::variant(&cx.types[ty], n, v)?.store(cx, offset) 606 } 607 (InterfaceType::Variant(_), _) => unexpected(ty, self), 608 (InterfaceType::Enum(ty), Val::Enum(v)) => { 609 GenericVariant::enum_(&cx.types[ty], v)?.store(cx, offset) 610 } 611 (InterfaceType::Enum(_), _) => unexpected(ty, self), 612 (InterfaceType::Option(ty), Val::Option(v)) => { 613 GenericVariant::option(&cx.types[ty], v).store(cx, offset) 614 } 615 (InterfaceType::Option(_), _) => unexpected(ty, self), 616 (InterfaceType::Result(ty), Val::Result(v)) => { 617 GenericVariant::result(&cx.types[ty], v)?.store(cx, offset) 618 } 619 (InterfaceType::Result(_), _) => unexpected(ty, self), 620 621 (InterfaceType::Flags(ty), Val::Flags(flags)) => { 622 let ty = &cx.types[ty]; 623 let storage = flags_to_storage(ty, flags)?; 624 match FlagsSize::from_count(ty.names.len()) { 625 FlagsSize::Size0 => {} 626 FlagsSize::Size1 => u8::try_from(storage[0]).unwrap().linear_lower_to_memory( 627 cx, 628 InterfaceType::U8, 629 offset, 630 )?, 631 FlagsSize::Size2 => u16::try_from(storage[0]).unwrap().linear_lower_to_memory( 632 cx, 633 InterfaceType::U16, 634 offset, 635 )?, 636 FlagsSize::Size4Plus(_) => { 637 let mut offset = offset; 638 for value in storage { 639 value.linear_lower_to_memory(cx, InterfaceType::U32, offset)?; 640 offset += 4; 641 } 642 } 643 } 644 Ok(()) 645 } 646 (InterfaceType::Flags(_), _) => unexpected(ty, self), 647 (InterfaceType::Future(_), Val::Future(FutureAny(rep))) => { 648 concurrent::lower_future_to_index::<T>(*rep, cx, ty)?.linear_lower_to_memory( 649 cx, 650 InterfaceType::U32, 651 offset, 652 ) 653 } 654 (InterfaceType::Future(_), _) => unexpected(ty, self), 655 (InterfaceType::Stream(_), Val::Stream(StreamAny(rep))) => { 656 concurrent::lower_stream_to_index::<T>(*rep, cx, ty)?.linear_lower_to_memory( 657 cx, 658 InterfaceType::U32, 659 offset, 660 ) 661 } 662 (InterfaceType::Stream(_), _) => unexpected(ty, self), 663 (InterfaceType::ErrorContext(_), Val::ErrorContext(ErrorContextAny(rep))) => { 664 concurrent::lower_error_context_to_index(*rep, cx, ty)?.linear_lower_to_memory( 665 cx, 666 InterfaceType::U32, 667 offset, 668 ) 669 } 670 (InterfaceType::ErrorContext(_), _) => unexpected(ty, self), 671 } 672 } 673 674 pub(crate) fn desc(&self) -> &'static str { 675 match self { 676 Val::Bool(_) => "bool", 677 Val::U8(_) => "u8", 678 Val::S8(_) => "s8", 679 Val::U16(_) => "u16", 680 Val::S16(_) => "s16", 681 Val::U32(_) => "u32", 682 Val::S32(_) => "s32", 683 Val::U64(_) => "u64", 684 Val::S64(_) => "s64", 685 Val::Float32(_) => "f32", 686 Val::Float64(_) => "f64", 687 Val::Char(_) => "char", 688 Val::List(_) => "list", 689 Val::String(_) => "string", 690 Val::Record(_) => "record", 691 Val::Enum(_) => "enum", 692 Val::Variant(..) => "variant", 693 Val::Tuple(_) => "tuple", 694 Val::Option(_) => "option", 695 Val::Result(_) => "result", 696 Val::Resource(_) => "resource", 697 Val::Flags(_) => "flags", 698 Val::Future(_) => "future", 699 Val::Stream(_) => "stream", 700 Val::ErrorContext(_) => "error-context", 701 } 702 } 703 704 /// Deserialize a [`Val`] from its [`crate::component::wasm_wave`] encoding. Deserialization 705 /// requires a target [`crate::component::Type`]. 706 #[cfg(feature = "wave")] 707 pub fn from_wave(ty: &crate::component::Type, s: &str) -> Result<Self> { 708 Ok(wasm_wave::from_str(ty, s)?) 709 } 710 711 /// Serialize a [`Val`] to its [`crate::component::wasm_wave`] encoding. 712 #[cfg(feature = "wave")] 713 pub fn to_wave(&self) -> Result<String> { 714 Ok(wasm_wave::to_string(self)?) 715 } 716 } 717 718 impl PartialEq for Val { 719 fn eq(&self, other: &Self) -> bool { 720 match (self, other) { 721 // IEEE 754 equality considers NaN inequal to NaN and negative zero 722 // equal to positive zero, however we do the opposite here, because 723 // this logic is used by testing and fuzzing, which want to know 724 // whether two values are semantically the same, rather than 725 // numerically equal. 726 (Self::Float32(l), Self::Float32(r)) => { 727 (*l != 0.0 && l == r) 728 || (*l == 0.0 && l.to_bits() == r.to_bits()) 729 || (l.is_nan() && r.is_nan()) 730 } 731 (Self::Float32(_), _) => false, 732 (Self::Float64(l), Self::Float64(r)) => { 733 (*l != 0.0 && l == r) 734 || (*l == 0.0 && l.to_bits() == r.to_bits()) 735 || (l.is_nan() && r.is_nan()) 736 } 737 (Self::Float64(_), _) => false, 738 739 (Self::Bool(l), Self::Bool(r)) => l == r, 740 (Self::Bool(_), _) => false, 741 (Self::S8(l), Self::S8(r)) => l == r, 742 (Self::S8(_), _) => false, 743 (Self::U8(l), Self::U8(r)) => l == r, 744 (Self::U8(_), _) => false, 745 (Self::S16(l), Self::S16(r)) => l == r, 746 (Self::S16(_), _) => false, 747 (Self::U16(l), Self::U16(r)) => l == r, 748 (Self::U16(_), _) => false, 749 (Self::S32(l), Self::S32(r)) => l == r, 750 (Self::S32(_), _) => false, 751 (Self::U32(l), Self::U32(r)) => l == r, 752 (Self::U32(_), _) => false, 753 (Self::S64(l), Self::S64(r)) => l == r, 754 (Self::S64(_), _) => false, 755 (Self::U64(l), Self::U64(r)) => l == r, 756 (Self::U64(_), _) => false, 757 (Self::Char(l), Self::Char(r)) => l == r, 758 (Self::Char(_), _) => false, 759 (Self::String(l), Self::String(r)) => l == r, 760 (Self::String(_), _) => false, 761 (Self::List(l), Self::List(r)) => l == r, 762 (Self::List(_), _) => false, 763 (Self::Record(l), Self::Record(r)) => l == r, 764 (Self::Record(_), _) => false, 765 (Self::Tuple(l), Self::Tuple(r)) => l == r, 766 (Self::Tuple(_), _) => false, 767 (Self::Variant(ln, lv), Self::Variant(rn, rv)) => ln == rn && lv == rv, 768 (Self::Variant(..), _) => false, 769 (Self::Enum(l), Self::Enum(r)) => l == r, 770 (Self::Enum(_), _) => false, 771 (Self::Option(l), Self::Option(r)) => l == r, 772 (Self::Option(_), _) => false, 773 (Self::Result(l), Self::Result(r)) => l == r, 774 (Self::Result(_), _) => false, 775 (Self::Flags(l), Self::Flags(r)) => l == r, 776 (Self::Flags(_), _) => false, 777 (Self::Resource(l), Self::Resource(r)) => l == r, 778 (Self::Resource(_), _) => false, 779 (Self::Future(l), Self::Future(r)) => l == r, 780 (Self::Future(_), _) => false, 781 (Self::Stream(l), Self::Stream(r)) => l == r, 782 (Self::Stream(_), _) => false, 783 (Self::ErrorContext(l), Self::ErrorContext(r)) => l == r, 784 (Self::ErrorContext(_), _) => false, 785 } 786 } 787 } 788 789 impl Eq for Val {} 790 791 struct GenericVariant<'a> { 792 discriminant: u32, 793 payload: Option<(&'a Val, InterfaceType)>, 794 abi: &'a CanonicalAbiInfo, 795 info: &'a VariantInfo, 796 } 797 798 impl GenericVariant<'_> { 799 fn result<'a>( 800 ty: &'a TypeResult, 801 r: &'a Result<Option<Box<Val>>, Option<Box<Val>>>, 802 ) -> Result<GenericVariant<'a>> { 803 let (discriminant, payload) = match r { 804 Ok(val) => { 805 let payload = match (val, ty.ok) { 806 (Some(val), Some(ty)) => Some((&**val, ty)), 807 (None, None) => None, 808 (Some(_), None) => { 809 bail!("payload provided to `ok` but not expected"); 810 } 811 (None, Some(_)) => { 812 bail!("payload expected to `ok` but not provided"); 813 } 814 }; 815 (0, payload) 816 } 817 Err(val) => { 818 let payload = match (val, ty.err) { 819 (Some(val), Some(ty)) => Some((&**val, ty)), 820 (None, None) => None, 821 (Some(_), None) => { 822 bail!("payload provided to `err` but not expected"); 823 } 824 (None, Some(_)) => { 825 bail!("payload expected to `err` but not provided"); 826 } 827 }; 828 (1, payload) 829 } 830 }; 831 Ok(GenericVariant { 832 discriminant, 833 payload, 834 abi: &ty.abi, 835 info: &ty.info, 836 }) 837 } 838 839 fn option<'a>(ty: &'a TypeOption, r: &'a Option<Box<Val>>) -> GenericVariant<'a> { 840 let (discriminant, payload) = match r { 841 None => (0, None), 842 Some(val) => (1, Some((&**val, ty.ty))), 843 }; 844 GenericVariant { 845 discriminant, 846 payload, 847 abi: &ty.abi, 848 info: &ty.info, 849 } 850 } 851 852 fn enum_<'a>(ty: &'a TypeEnum, discriminant: &str) -> Result<GenericVariant<'a>> { 853 let discriminant = get_enum_discriminant(ty, discriminant)?; 854 855 Ok(GenericVariant { 856 discriminant, 857 payload: None, 858 abi: &ty.abi, 859 info: &ty.info, 860 }) 861 } 862 863 fn variant<'a>( 864 ty: &'a TypeVariant, 865 discriminant_name: &str, 866 payload: &'a Option<Box<Val>>, 867 ) -> Result<GenericVariant<'a>> { 868 let (discriminant, payload_ty) = get_variant_discriminant(ty, discriminant_name)?; 869 870 let payload = match (payload, payload_ty) { 871 (Some(val), Some(ty)) => Some((&**val, *ty)), 872 (None, None) => None, 873 (Some(_), None) => bail!("did not expect a payload for case `{discriminant_name}`"), 874 (None, Some(_)) => bail!("expected a payload for case `{discriminant_name}`"), 875 }; 876 877 Ok(GenericVariant { 878 discriminant, 879 payload, 880 abi: &ty.abi, 881 info: &ty.info, 882 }) 883 } 884 885 fn lower<T>( 886 &self, 887 cx: &mut LowerContext<'_, T>, 888 dst: &mut IterMut<'_, MaybeUninit<ValRaw>>, 889 ) -> Result<()> { 890 next_mut(dst).write(ValRaw::u32(self.discriminant)); 891 892 // For the remaining lowered representation of this variant that 893 // the payload didn't write we write out zeros here to ensure 894 // the entire variant is written. 895 let value_flat = match self.payload { 896 Some((value, ty)) => { 897 value.lower(cx, ty, dst)?; 898 cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap() 899 } 900 None => 0, 901 }; 902 let variant_flat = self.abi.flat_count(usize::MAX).unwrap(); 903 for _ in (1 + value_flat)..variant_flat { 904 next_mut(dst).write(ValRaw::u64(0)); 905 } 906 Ok(()) 907 } 908 909 fn store<T>(&self, cx: &mut LowerContext<'_, T>, offset: usize) -> Result<()> { 910 match self.info.size { 911 DiscriminantSize::Size1 => u8::try_from(self.discriminant) 912 .unwrap() 913 .linear_lower_to_memory(cx, InterfaceType::U8, offset)?, 914 DiscriminantSize::Size2 => u16::try_from(self.discriminant) 915 .unwrap() 916 .linear_lower_to_memory(cx, InterfaceType::U16, offset)?, 917 DiscriminantSize::Size4 => { 918 self.discriminant 919 .linear_lower_to_memory(cx, InterfaceType::U32, offset)? 920 } 921 } 922 923 if let Some((value, ty)) = self.payload { 924 let offset = offset + usize::try_from(self.info.payload_offset32).unwrap(); 925 value.store(cx, ty, offset)?; 926 } 927 928 Ok(()) 929 } 930 } 931 932 fn load_list(cx: &mut LiftContext<'_>, ty: TypeListIndex, ptr: usize, len: usize) -> Result<Val> { 933 let elem = cx.types[ty].element; 934 let abi = cx.types.canonical_abi(&elem); 935 let element_size = usize::try_from(abi.size32).unwrap(); 936 let element_alignment = abi.align32; 937 938 match len 939 .checked_mul(element_size) 940 .and_then(|len| ptr.checked_add(len)) 941 { 942 Some(n) if n <= cx.memory().len() => {} 943 _ => bail!("list pointer/length out of bounds of memory"), 944 } 945 if ptr % usize::try_from(element_alignment)? != 0 { 946 bail!("list pointer is not aligned") 947 } 948 949 Ok(Val::List( 950 (0..len) 951 .map(|index| { 952 Val::load( 953 cx, 954 elem, 955 &cx.memory()[ptr + (index * element_size)..][..element_size], 956 ) 957 }) 958 .collect::<Result<_>>()?, 959 )) 960 } 961 962 fn load_variant( 963 cx: &mut LiftContext<'_>, 964 info: &VariantInfo, 965 mut types: impl ExactSizeIterator<Item = Option<InterfaceType>>, 966 bytes: &[u8], 967 ) -> Result<(u32, Option<Box<Val>>)> { 968 let discriminant = match info.size { 969 DiscriminantSize::Size1 => u32::from(u8::linear_lift_from_memory( 970 cx, 971 InterfaceType::U8, 972 &bytes[..1], 973 )?), 974 DiscriminantSize::Size2 => u32::from(u16::linear_lift_from_memory( 975 cx, 976 InterfaceType::U16, 977 &bytes[..2], 978 )?), 979 DiscriminantSize::Size4 => { 980 u32::linear_lift_from_memory(cx, InterfaceType::U32, &bytes[..4])? 981 } 982 }; 983 let case_ty = types.nth(discriminant as usize).ok_or_else(|| { 984 anyhow!( 985 "discriminant {} out of range [0..{})", 986 discriminant, 987 types.len() 988 ) 989 })?; 990 let value = match case_ty { 991 Some(case_ty) => { 992 let payload_offset = usize::try_from(info.payload_offset32).unwrap(); 993 let case_abi = cx.types.canonical_abi(&case_ty); 994 let case_size = usize::try_from(case_abi.size32).unwrap(); 995 Some(Box::new(Val::load( 996 cx, 997 case_ty, 998 &bytes[payload_offset..][..case_size], 999 )?)) 1000 } 1001 None => None, 1002 }; 1003 Ok((discriminant, value)) 1004 } 1005 1006 fn lift_variant( 1007 cx: &mut LiftContext<'_>, 1008 flatten_count: usize, 1009 mut types: impl ExactSizeIterator<Item = Option<InterfaceType>>, 1010 src: &mut Iter<'_, ValRaw>, 1011 ) -> Result<(u32, Option<Box<Val>>)> { 1012 let len = types.len(); 1013 let discriminant = next(src).get_u32(); 1014 let ty = types 1015 .nth(discriminant as usize) 1016 .ok_or_else(|| anyhow!("discriminant {} out of range [0..{})", discriminant, len))?; 1017 let (value, value_flat) = match ty { 1018 Some(ty) => ( 1019 Some(Box::new(Val::lift(cx, ty, src)?)), 1020 cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(), 1021 ), 1022 None => (None, 0), 1023 }; 1024 for _ in (1 + value_flat)..flatten_count { 1025 next(src); 1026 } 1027 Ok((discriminant, value)) 1028 } 1029 1030 /// Lower a list with the specified element type and values. 1031 fn lower_list<T>( 1032 cx: &mut LowerContext<'_, T>, 1033 element_type: InterfaceType, 1034 items: &[Val], 1035 ) -> Result<(usize, usize)> { 1036 let abi = cx.types.canonical_abi(&element_type); 1037 let elt_size = usize::try_from(abi.size32)?; 1038 let elt_align = abi.align32; 1039 let size = items 1040 .len() 1041 .checked_mul(elt_size) 1042 .ok_or_else(|| anyhow::anyhow!("size overflow copying a list"))?; 1043 let ptr = cx.realloc(0, 0, elt_align, size)?; 1044 let mut element_ptr = ptr; 1045 for item in items { 1046 item.store(cx, element_type, element_ptr)?; 1047 element_ptr += elt_size; 1048 } 1049 Ok((ptr, items.len())) 1050 } 1051 1052 fn push_flags(ty: &TypeFlags, flags: &mut Vec<String>, mut offset: u32, mut bits: u32) { 1053 while bits > 0 { 1054 if bits & 1 != 0 { 1055 flags.push(ty.names[offset as usize].clone()); 1056 } 1057 bits >>= 1; 1058 offset += 1; 1059 } 1060 } 1061 1062 fn flags_to_storage(ty: &TypeFlags, flags: &[String]) -> Result<Vec<u32>> { 1063 let mut storage = match FlagsSize::from_count(ty.names.len()) { 1064 FlagsSize::Size0 => Vec::new(), 1065 FlagsSize::Size1 | FlagsSize::Size2 => vec![0], 1066 FlagsSize::Size4Plus(n) => vec![0; n.into()], 1067 }; 1068 1069 for flag in flags { 1070 let bit = ty 1071 .names 1072 .get_index_of(flag) 1073 .ok_or_else(|| anyhow::anyhow!("unknown flag: `{flag}`"))?; 1074 storage[bit / 32] |= 1 << (bit % 32); 1075 } 1076 Ok(storage) 1077 } 1078 1079 fn get_enum_discriminant(ty: &TypeEnum, n: &str) -> Result<u32> { 1080 ty.names 1081 .get_index_of(n) 1082 .ok_or_else(|| anyhow::anyhow!("enum variant name `{n}` is not valid")) 1083 .map(|i| i.try_into().unwrap()) 1084 } 1085 1086 fn get_variant_discriminant<'a>( 1087 ty: &'a TypeVariant, 1088 name: &str, 1089 ) -> Result<(u32, &'a Option<InterfaceType>)> { 1090 let (i, _, ty) = ty 1091 .cases 1092 .get_full(name) 1093 .ok_or_else(|| anyhow::anyhow!("unknown variant case: `{name}`"))?; 1094 Ok((i.try_into().unwrap(), ty)) 1095 } 1096 1097 fn next<'a>(src: &mut Iter<'a, ValRaw>) -> &'a ValRaw { 1098 src.next().unwrap() 1099 } 1100 1101 fn next_mut<'a>(dst: &mut IterMut<'a, MaybeUninit<ValRaw>>) -> &'a mut MaybeUninit<ValRaw> { 1102 dst.next().unwrap() 1103 } 1104 1105 #[cold] 1106 fn unexpected<T>(ty: InterfaceType, val: &Val) -> Result<T> { 1107 bail!( 1108 "type mismatch: expected {}, found {}", 1109 desc(&ty), 1110 val.desc() 1111 ) 1112 } 1113 1114 /// Represents a component model `future`. 1115 /// 1116 /// Note that this type is not usable at this time as its implementation has not 1117 /// been filled out. There are no operations on this and there's additionally no 1118 /// ability to "drop" or deallocate this index. This means that from the 1119 /// perspective of wasm it'll appear that this handle has "leaked" without ever 1120 /// being dropped or read from. 1121 // 1122 // FIXME(#11161) this needs to be filled out implementation-wise 1123 #[derive(Debug, Clone, PartialEq, Eq)] 1124 pub struct FutureAny(pub(crate) u32); 1125 1126 /// Represents a component model `stream`. 1127 /// 1128 /// Note that this type is not usable at this time as its implementation has not 1129 /// been filled out. There are no operations on this and there's additionally no 1130 /// ability to "drop" or deallocate this index. This means that from the 1131 /// perspective of wasm it'll appear that this handle has "leaked" without ever 1132 /// being dropped or read from. 1133 // 1134 // FIXME(#11161) this needs to be filled out implementation-wise 1135 #[derive(Debug, Clone, PartialEq, Eq)] 1136 pub struct StreamAny(pub(crate) u32); 1137 1138 /// Represents a component model `error-context`. 1139 /// 1140 /// Note that this type is not usable at this time as its implementation has not 1141 /// been filled out. There are no operations on this and there's additionally no 1142 /// ability to "drop" or deallocate this index. 1143 // 1144 // FIXME(#11161) this needs to be filled out implementation-wise 1145 #[derive(Debug, Clone, PartialEq, Eq)] 1146 pub struct ErrorContextAny(pub(crate) u32); 1147