1 use proc_macro2::{Literal, TokenStream, TokenTree}; 2 use quote::{format_ident, quote}; 3 use std::collections::HashSet; 4 use std::fmt; 5 use syn::parse::{Parse, ParseStream}; 6 use syn::punctuated::Punctuated; 7 use syn::{braced, parse_quote, Data, DeriveInput, Error, Result, Token}; 8 use wasmtime_component_util::{DiscriminantSize, FlagsSize}; 9 10 #[derive(Debug, Copy, Clone)] 11 pub enum VariantStyle { 12 Variant, 13 Enum, 14 Union, 15 } 16 17 impl fmt::Display for VariantStyle { 18 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 19 f.write_str(match self { 20 Self::Variant => "variant", 21 Self::Enum => "enum", 22 Self::Union => "union", 23 }) 24 } 25 } 26 27 #[derive(Debug, Copy, Clone)] 28 enum Style { 29 Record, 30 Variant(VariantStyle), 31 } 32 33 fn find_style(input: &DeriveInput) -> Result<Style> { 34 let mut style = None; 35 36 for attribute in &input.attrs { 37 if attribute.path.leading_colon.is_some() || attribute.path.segments.len() != 1 { 38 continue; 39 } 40 41 let ident = &attribute.path.segments[0].ident; 42 43 if "component" != &ident.to_string() { 44 continue; 45 } 46 47 let syntax_error = || { 48 Err(Error::new_spanned( 49 &attribute.tokens, 50 "expected `component(<style>)` syntax", 51 )) 52 }; 53 54 let style_string = if let [TokenTree::Group(group)] = 55 &attribute.tokens.clone().into_iter().collect::<Vec<_>>()[..] 56 { 57 if let [TokenTree::Ident(style)] = &group.stream().into_iter().collect::<Vec<_>>()[..] { 58 style.to_string() 59 } else { 60 return syntax_error(); 61 } 62 } else { 63 return syntax_error(); 64 }; 65 66 if style.is_some() { 67 return Err(Error::new(ident.span(), "duplicate `component` attribute")); 68 } 69 70 style = Some(match style_string.as_ref() { 71 "record" => Style::Record, 72 "variant" => Style::Variant(VariantStyle::Variant), 73 "enum" => Style::Variant(VariantStyle::Enum), 74 "union" => Style::Variant(VariantStyle::Union), 75 "flags" => { 76 return Err(Error::new_spanned( 77 &attribute.tokens, 78 "`flags` not allowed here; \ 79 use `wasmtime::component::flags!` macro to define `flags` types", 80 )) 81 } 82 _ => { 83 return Err(Error::new_spanned( 84 &attribute.tokens, 85 "unrecognized component type keyword \ 86 (expected `record`, `variant`, `enum`, or `union`)", 87 )) 88 } 89 }); 90 } 91 92 style.ok_or_else(|| Error::new_spanned(input, "missing `component` attribute")) 93 } 94 95 fn find_rename(attributes: &[syn::Attribute]) -> Result<Option<Literal>> { 96 let mut name = None; 97 98 for attribute in attributes { 99 if attribute.path.leading_colon.is_some() || attribute.path.segments.len() != 1 { 100 continue; 101 } 102 103 let ident = &attribute.path.segments[0].ident; 104 105 if "component" != &ident.to_string() { 106 continue; 107 } 108 109 let syntax_error = || { 110 Err(Error::new_spanned( 111 &attribute.tokens, 112 "expected `component(name = <name literal>)` syntax", 113 )) 114 }; 115 116 let name_literal = if let [TokenTree::Group(group)] = 117 &attribute.tokens.clone().into_iter().collect::<Vec<_>>()[..] 118 { 119 match &group.stream().into_iter().collect::<Vec<_>>()[..] { 120 [TokenTree::Ident(key), TokenTree::Punct(op), TokenTree::Literal(literal)] 121 if "name" == &key.to_string() && '=' == op.as_char() => 122 { 123 literal.clone() 124 } 125 _ => return syntax_error(), 126 } 127 } else { 128 return syntax_error(); 129 }; 130 131 if name.is_some() { 132 return Err(Error::new(ident.span(), "duplicate field rename attribute")); 133 } 134 135 name = Some(name_literal); 136 } 137 138 Ok(name) 139 } 140 141 fn add_trait_bounds(generics: &syn::Generics, bound: syn::TypeParamBound) -> syn::Generics { 142 let mut generics = generics.clone(); 143 for param in &mut generics.params { 144 if let syn::GenericParam::Type(ref mut type_param) = *param { 145 type_param.bounds.push(bound.clone()); 146 } 147 } 148 generics 149 } 150 151 pub struct VariantCase<'a> { 152 attrs: &'a [syn::Attribute], 153 ident: &'a syn::Ident, 154 ty: Option<&'a syn::Type>, 155 } 156 157 pub trait Expander { 158 fn expand_record( 159 &self, 160 name: &syn::Ident, 161 generics: &syn::Generics, 162 fields: &[&syn::Field], 163 ) -> Result<TokenStream>; 164 165 fn expand_variant( 166 &self, 167 name: &syn::Ident, 168 generics: &syn::Generics, 169 discriminant_size: DiscriminantSize, 170 cases: &[VariantCase], 171 style: VariantStyle, 172 ) -> Result<TokenStream>; 173 } 174 175 pub fn expand(expander: &dyn Expander, input: &DeriveInput) -> Result<TokenStream> { 176 match find_style(input)? { 177 Style::Record => expand_record(expander, input), 178 Style::Variant(style) => expand_variant(expander, input, style), 179 } 180 } 181 182 fn expand_record(expander: &dyn Expander, input: &DeriveInput) -> Result<TokenStream> { 183 let name = &input.ident; 184 185 let body = if let Data::Struct(body) = &input.data { 186 body 187 } else { 188 return Err(Error::new( 189 name.span(), 190 "`record` component types can only be derived for Rust `struct`s", 191 )); 192 }; 193 194 match &body.fields { 195 syn::Fields::Named(fields) => expander.expand_record( 196 &input.ident, 197 &input.generics, 198 &fields.named.iter().collect::<Vec<_>>(), 199 ), 200 201 syn::Fields::Unnamed(_) | syn::Fields::Unit => Err(Error::new( 202 name.span(), 203 "`record` component types can only be derived for `struct`s with named fields", 204 )), 205 } 206 } 207 208 fn expand_variant( 209 expander: &dyn Expander, 210 input: &DeriveInput, 211 style: VariantStyle, 212 ) -> Result<TokenStream> { 213 let name = &input.ident; 214 215 let body = if let Data::Enum(body) = &input.data { 216 body 217 } else { 218 return Err(Error::new( 219 name.span(), 220 format!( 221 "`{}` component types can only be derived for Rust `enum`s", 222 style 223 ), 224 )); 225 }; 226 227 if body.variants.is_empty() { 228 return Err(Error::new( 229 name.span(), 230 format!("`{}` component types can only be derived for Rust `enum`s with at least one variant", style), 231 )); 232 } 233 234 let discriminant_size = DiscriminantSize::from_count(body.variants.len()).ok_or_else(|| { 235 Error::new( 236 input.ident.span(), 237 "`enum`s with more than 2^32 variants are not supported", 238 ) 239 })?; 240 241 let cases = body 242 .variants 243 .iter() 244 .map( 245 |syn::Variant { 246 attrs, 247 ident, 248 fields, 249 .. 250 }| { 251 Ok(VariantCase { 252 attrs, 253 ident, 254 ty: match fields { 255 syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => { 256 Some(&fields.unnamed[0].ty) 257 } 258 syn::Fields::Unit => None, 259 _ => { 260 return Err(Error::new( 261 name.span(), 262 format!( 263 "`{}` component types can only be derived for Rust `enum`s \ 264 containing variants with {}", 265 style, 266 match style { 267 VariantStyle::Variant => "at most one unnamed field each", 268 VariantStyle::Enum => "no fields", 269 VariantStyle::Union => "exactly one unnamed field each", 270 } 271 ), 272 )) 273 } 274 }, 275 }) 276 }, 277 ) 278 .collect::<Result<Vec<_>>>()?; 279 280 expander.expand_variant( 281 &input.ident, 282 &input.generics, 283 discriminant_size, 284 &cases, 285 style, 286 ) 287 } 288 289 fn expand_record_for_component_type( 290 name: &syn::Ident, 291 generics: &syn::Generics, 292 fields: &[&syn::Field], 293 typecheck: TokenStream, 294 typecheck_argument: TokenStream, 295 ) -> Result<TokenStream> { 296 let internal = quote!(wasmtime::component::__internal); 297 298 let mut lower_generic_params = TokenStream::new(); 299 let mut lower_generic_args = TokenStream::new(); 300 let mut lower_field_declarations = TokenStream::new(); 301 let mut abi_list = TokenStream::new(); 302 let mut unique_types = HashSet::new(); 303 304 for (index, syn::Field { ident, ty, .. }) in fields.iter().enumerate() { 305 let generic = format_ident!("T{}", index); 306 307 lower_generic_params.extend(quote!(#generic: Copy,)); 308 lower_generic_args.extend(quote!(<#ty as wasmtime::component::ComponentType>::Lower,)); 309 310 lower_field_declarations.extend(quote!(#ident: #generic,)); 311 312 abi_list.extend(quote!( 313 <#ty as wasmtime::component::ComponentType>::ABI, 314 )); 315 316 unique_types.insert(ty); 317 } 318 319 let generics = add_trait_bounds(generics, parse_quote!(wasmtime::component::ComponentType)); 320 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 321 let lower = format_ident!("Lower{}", name); 322 323 // You may wonder why we make the types of all the fields of the #lower struct generic. This is to work 324 // around the lack of [perfect derive support in 325 // rustc](https://smallcultfollowing.com/babysteps//blog/2022/04/12/implied-bounds-and-perfect-derive/#what-is-perfect-derive) 326 // as of this writing. 327 // 328 // If the struct we're deriving a `ComponentType` impl for has any generic parameters, then #lower needs 329 // generic parameters too. And if we just copy the parameters and bounds from the impl to #lower, then the 330 // `#[derive(Clone, Copy)]` will fail unless the original generics were declared with those bounds, which 331 // we don't want to require. 332 // 333 // Alternatively, we could just pass the `Lower` associated type of each generic type as arguments to 334 // #lower, but that would require distinguishing between generic and concrete types when generating 335 // #lower_field_declarations, which would require some form of symbol resolution. That doesn't seem worth 336 // the trouble. 337 338 let expanded = quote! { 339 #[doc(hidden)] 340 #[derive(Clone, Copy)] 341 #[repr(C)] 342 pub struct #lower <#lower_generic_params> { 343 #lower_field_declarations 344 _align: [wasmtime::ValRaw; 0], 345 } 346 347 unsafe impl #impl_generics wasmtime::component::ComponentType for #name #ty_generics #where_clause { 348 type Lower = #lower <#lower_generic_args>; 349 350 const ABI: #internal::CanonicalAbiInfo = 351 #internal::CanonicalAbiInfo::record_static(&[#abi_list]); 352 353 #[inline] 354 fn typecheck( 355 ty: &#internal::InterfaceType, 356 types: &#internal::ComponentTypes, 357 ) -> #internal::anyhow::Result<()> { 358 #internal::#typecheck(ty, types, &[#typecheck_argument]) 359 } 360 } 361 }; 362 363 Ok(quote!(const _: () = { #expanded };)) 364 } 365 366 fn quote(size: DiscriminantSize, discriminant: usize) -> TokenStream { 367 match size { 368 DiscriminantSize::Size1 => { 369 let discriminant = u8::try_from(discriminant).unwrap(); 370 quote!(#discriminant) 371 } 372 DiscriminantSize::Size2 => { 373 let discriminant = u16::try_from(discriminant).unwrap(); 374 quote!(#discriminant) 375 } 376 DiscriminantSize::Size4 => { 377 let discriminant = u32::try_from(discriminant).unwrap(); 378 quote!(#discriminant) 379 } 380 } 381 } 382 383 pub struct LiftExpander; 384 385 impl Expander for LiftExpander { 386 fn expand_record( 387 &self, 388 name: &syn::Ident, 389 generics: &syn::Generics, 390 fields: &[&syn::Field], 391 ) -> Result<TokenStream> { 392 let internal = quote!(wasmtime::component::__internal); 393 394 let mut lifts = TokenStream::new(); 395 let mut loads = TokenStream::new(); 396 397 for syn::Field { ident, ty, .. } in fields { 398 lifts.extend(quote!(#ident: <#ty as wasmtime::component::Lift>::lift( 399 store, options, &src.#ident 400 )?,)); 401 402 loads.extend(quote!(#ident: <#ty as wasmtime::component::Lift>::load( 403 memory, 404 &bytes 405 [<#ty as wasmtime::component::ComponentType>::ABI.next_field32_size(&mut offset)..] 406 [..<#ty as wasmtime::component::ComponentType>::SIZE32] 407 )?,)); 408 } 409 410 let generics = add_trait_bounds(generics, parse_quote!(wasmtime::component::Lift)); 411 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 412 413 let expanded = quote! { 414 unsafe impl #impl_generics wasmtime::component::Lift for #name #ty_generics #where_clause { 415 #[inline] 416 fn lift( 417 store: &#internal::StoreOpaque, 418 options: &#internal::Options, 419 src: &Self::Lower, 420 ) -> #internal::anyhow::Result<Self> { 421 Ok(Self { 422 #lifts 423 }) 424 } 425 426 #[inline] 427 fn load(memory: &#internal::Memory, bytes: &[u8]) -> #internal::anyhow::Result<Self> { 428 debug_assert!( 429 (bytes.as_ptr() as usize) 430 % (<Self as wasmtime::component::ComponentType>::ALIGN32 as usize) 431 == 0 432 ); 433 let mut offset = 0; 434 Ok(Self { 435 #loads 436 }) 437 } 438 } 439 }; 440 441 Ok(expanded) 442 } 443 444 fn expand_variant( 445 &self, 446 name: &syn::Ident, 447 generics: &syn::Generics, 448 discriminant_size: DiscriminantSize, 449 cases: &[VariantCase], 450 _style: VariantStyle, 451 ) -> Result<TokenStream> { 452 let internal = quote!(wasmtime::component::__internal); 453 454 let mut lifts = TokenStream::new(); 455 let mut loads = TokenStream::new(); 456 457 for (index, VariantCase { ident, ty, .. }) in cases.iter().enumerate() { 458 let index_u32 = u32::try_from(index).unwrap(); 459 460 let index_quoted = quote(discriminant_size, index); 461 462 if let Some(ty) = ty { 463 lifts.extend( 464 quote!(#index_u32 => Self::#ident(<#ty as wasmtime::component::Lift>::lift( 465 store, options, unsafe { &src.payload.#ident } 466 )?),), 467 ); 468 469 loads.extend( 470 quote!(#index_quoted => Self::#ident(<#ty as wasmtime::component::Lift>::load( 471 memory, &payload[..<#ty as wasmtime::component::ComponentType>::SIZE32] 472 )?),), 473 ); 474 } else { 475 lifts.extend(quote!(#index_u32 => Self::#ident,)); 476 477 loads.extend(quote!(#index_quoted => Self::#ident,)); 478 } 479 } 480 481 let generics = add_trait_bounds(generics, parse_quote!(wasmtime::component::Lift)); 482 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 483 484 let from_bytes = match discriminant_size { 485 DiscriminantSize::Size1 => quote!(bytes[0]), 486 DiscriminantSize::Size2 => quote!(u16::from_le_bytes(bytes[0..2].try_into()?)), 487 DiscriminantSize::Size4 => quote!(u32::from_le_bytes(bytes[0..4].try_into()?)), 488 }; 489 490 let expanded = quote! { 491 unsafe impl #impl_generics wasmtime::component::Lift for #name #ty_generics #where_clause { 492 #[inline] 493 fn lift( 494 store: &#internal::StoreOpaque, 495 options: &#internal::Options, 496 src: &Self::Lower, 497 ) -> #internal::anyhow::Result<Self> { 498 Ok(match src.tag.get_u32() { 499 #lifts 500 discrim => #internal::anyhow::bail!("unexpected discriminant: {}", discrim), 501 }) 502 } 503 504 #[inline] 505 fn load(memory: &#internal::Memory, bytes: &[u8]) -> #internal::anyhow::Result<Self> { 506 let align = <Self as wasmtime::component::ComponentType>::ALIGN32; 507 debug_assert!((bytes.as_ptr() as usize) % (align as usize) == 0); 508 let discrim = #from_bytes; 509 let payload_offset = <Self as #internal::ComponentVariant>::PAYLOAD_OFFSET32; 510 let payload = &bytes[payload_offset..]; 511 Ok(match discrim { 512 #loads 513 discrim => #internal::anyhow::bail!("unexpected discriminant: {}", discrim), 514 }) 515 } 516 } 517 }; 518 519 Ok(expanded) 520 } 521 } 522 523 pub struct LowerExpander; 524 525 impl Expander for LowerExpander { 526 fn expand_record( 527 &self, 528 name: &syn::Ident, 529 generics: &syn::Generics, 530 fields: &[&syn::Field], 531 ) -> Result<TokenStream> { 532 let internal = quote!(wasmtime::component::__internal); 533 534 let mut lowers = TokenStream::new(); 535 let mut stores = TokenStream::new(); 536 537 for syn::Field { ident, ty, .. } in fields { 538 lowers.extend(quote!(wasmtime::component::Lower::lower( 539 &self.#ident, store, options, #internal::map_maybe_uninit!(dst.#ident) 540 )?;)); 541 542 stores.extend(quote!(wasmtime::component::Lower::store( 543 &self.#ident, 544 memory, 545 <#ty as wasmtime::component::ComponentType>::ABI.next_field32_size(&mut offset), 546 )?;)); 547 } 548 549 let generics = add_trait_bounds(generics, parse_quote!(wasmtime::component::Lower)); 550 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 551 552 let expanded = quote! { 553 unsafe impl #impl_generics wasmtime::component::Lower for #name #ty_generics #where_clause { 554 #[inline] 555 fn lower<T>( 556 &self, 557 store: &mut wasmtime::StoreContextMut<T>, 558 options: &#internal::Options, 559 dst: &mut std::mem::MaybeUninit<Self::Lower>, 560 ) -> #internal::anyhow::Result<()> { 561 #lowers 562 Ok(()) 563 } 564 565 #[inline] 566 fn store<T>( 567 &self, 568 memory: &mut #internal::MemoryMut<'_, T>, 569 mut offset: usize 570 ) -> #internal::anyhow::Result<()> { 571 debug_assert!(offset % (<Self as wasmtime::component::ComponentType>::ALIGN32 as usize) == 0); 572 #stores 573 Ok(()) 574 } 575 } 576 }; 577 578 Ok(expanded) 579 } 580 581 fn expand_variant( 582 &self, 583 name: &syn::Ident, 584 generics: &syn::Generics, 585 discriminant_size: DiscriminantSize, 586 cases: &[VariantCase], 587 _style: VariantStyle, 588 ) -> Result<TokenStream> { 589 let internal = quote!(wasmtime::component::__internal); 590 591 let mut lowers = TokenStream::new(); 592 let mut stores = TokenStream::new(); 593 594 for (index, VariantCase { ident, ty, .. }) in cases.iter().enumerate() { 595 let index_u32 = u32::try_from(index).unwrap(); 596 597 let index_quoted = quote(discriminant_size, index); 598 599 let discriminant_size = usize::from(discriminant_size); 600 601 let pattern; 602 let lower; 603 let store; 604 605 if ty.is_some() { 606 pattern = quote!(Self::#ident(value)); 607 lower = quote!(value.lower(store, options, dst)); 608 store = quote!(value.store( 609 memory, 610 offset + <Self as #internal::ComponentVariant>::PAYLOAD_OFFSET32, 611 )); 612 } else { 613 pattern = quote!(Self::#ident); 614 lower = quote!(Ok(())); 615 store = quote!(Ok(())); 616 } 617 618 lowers.extend(quote!(#pattern => { 619 #internal::map_maybe_uninit!(dst.tag).write(wasmtime::ValRaw::u32(#index_u32)); 620 unsafe { 621 #internal::lower_payload( 622 #internal::map_maybe_uninit!(dst.payload), 623 |payload| #internal::map_maybe_uninit!(payload.#ident), 624 |dst| #lower, 625 ) 626 } 627 })); 628 629 stores.extend(quote!(#pattern => { 630 *memory.get::<#discriminant_size>(offset) = #index_quoted.to_le_bytes(); 631 #store 632 })); 633 } 634 635 let generics = add_trait_bounds(generics, parse_quote!(wasmtime::component::Lower)); 636 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 637 638 let expanded = quote! { 639 unsafe impl #impl_generics wasmtime::component::Lower for #name #ty_generics #where_clause { 640 #[inline] 641 fn lower<T>( 642 &self, 643 store: &mut wasmtime::StoreContextMut<T>, 644 options: &#internal::Options, 645 dst: &mut std::mem::MaybeUninit<Self::Lower>, 646 ) -> #internal::anyhow::Result<()> { 647 match self { 648 #lowers 649 } 650 } 651 652 #[inline] 653 fn store<T>( 654 &self, 655 memory: &mut #internal::MemoryMut<'_, T>, 656 mut offset: usize 657 ) -> #internal::anyhow::Result<()> { 658 debug_assert!(offset % (<Self as wasmtime::component::ComponentType>::ALIGN32 as usize) == 0); 659 match self { 660 #stores 661 } 662 } 663 } 664 }; 665 666 Ok(expanded) 667 } 668 } 669 670 pub struct ComponentTypeExpander; 671 672 impl Expander for ComponentTypeExpander { 673 fn expand_record( 674 &self, 675 name: &syn::Ident, 676 generics: &syn::Generics, 677 fields: &[&syn::Field], 678 ) -> Result<TokenStream> { 679 expand_record_for_component_type( 680 name, 681 generics, 682 fields, 683 quote!(typecheck_record), 684 fields 685 .iter() 686 .map( 687 |syn::Field { 688 attrs, ident, ty, .. 689 }| { 690 let name = find_rename(attrs)?.unwrap_or_else(|| { 691 Literal::string(&ident.as_ref().unwrap().to_string()) 692 }); 693 694 Ok(quote!((#name, <#ty as wasmtime::component::ComponentType>::typecheck),)) 695 }, 696 ) 697 .collect::<Result<_>>()?, 698 ) 699 } 700 701 fn expand_variant( 702 &self, 703 name: &syn::Ident, 704 generics: &syn::Generics, 705 _discriminant_size: DiscriminantSize, 706 cases: &[VariantCase], 707 style: VariantStyle, 708 ) -> Result<TokenStream> { 709 let internal = quote!(wasmtime::component::__internal); 710 711 let mut case_names_and_checks = TokenStream::new(); 712 let mut lower_payload_generic_params = TokenStream::new(); 713 let mut lower_payload_generic_args = TokenStream::new(); 714 let mut lower_payload_case_declarations = TokenStream::new(); 715 let mut lower_generic_args = TokenStream::new(); 716 let mut abi_list = TokenStream::new(); 717 let mut unique_types = HashSet::new(); 718 719 for (index, VariantCase { attrs, ident, ty }) in cases.iter().enumerate() { 720 let rename = find_rename(attrs)?; 721 722 if let (Some(_), VariantStyle::Union) = (&rename, style) { 723 return Err(Error::new( 724 ident.span(), 725 "renaming `union` cases is not permitted; only the type is used", 726 )); 727 } 728 729 let name = rename.unwrap_or_else(|| Literal::string(&ident.to_string())); 730 731 if let Some(ty) = ty { 732 abi_list.extend(quote!(Some(<#ty as wasmtime::component::ComponentType>::ABI),)); 733 734 case_names_and_checks.extend(match style { 735 VariantStyle::Variant => { 736 quote!((#name, Some(<#ty as wasmtime::component::ComponentType>::typecheck)),) 737 } 738 VariantStyle::Union => { 739 quote!(<#ty as wasmtime::component::ComponentType>::typecheck,) 740 } 741 VariantStyle::Enum => { 742 return Err(Error::new( 743 ident.span(), 744 "payloads are not permitted for `enum` cases", 745 )) 746 } 747 }); 748 749 let generic = format_ident!("T{}", index); 750 751 lower_payload_generic_params.extend(quote!(#generic: Copy,)); 752 lower_payload_generic_args.extend(quote!(#generic,)); 753 lower_payload_case_declarations.extend(quote!(#ident: #generic,)); 754 lower_generic_args 755 .extend(quote!(<#ty as wasmtime::component::ComponentType>::Lower,)); 756 757 unique_types.insert(ty); 758 } else { 759 abi_list.extend(quote!(None,)); 760 case_names_and_checks.extend(match style { 761 VariantStyle::Variant => { 762 quote!((#name, None),) 763 } 764 VariantStyle::Union => { 765 quote!(<() as wasmtime::component::ComponentType>::typecheck,) 766 } 767 VariantStyle::Enum => quote!(#name,), 768 }); 769 lower_payload_case_declarations.extend(quote!(#ident: [wasmtime::ValRaw; 0],)); 770 } 771 } 772 773 let typecheck = match style { 774 VariantStyle::Variant => quote!(typecheck_variant), 775 VariantStyle::Union => quote!(typecheck_union), 776 VariantStyle::Enum => quote!(typecheck_enum), 777 }; 778 779 let generics = add_trait_bounds(generics, parse_quote!(wasmtime::component::ComponentType)); 780 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 781 let lower = format_ident!("Lower{}", name); 782 let lower_payload = format_ident!("LowerPayload{}", name); 783 784 // You may wonder why we make the types of all the fields of the #lower struct and #lower_payload union 785 // generic. This is to work around a [normalization bug in 786 // rustc](https://github.com/rust-lang/rust/issues/90903) such that the compiler does not understand that 787 // e.g. `<i32 as ComponentType>::Lower` is `Copy` despite the bound specified in `ComponentType`'s 788 // definition. 789 // 790 // See also the comment in `Self::expand_record` above for another reason why we do this. 791 792 let expanded = quote! { 793 #[doc(hidden)] 794 #[derive(Clone, Copy)] 795 #[repr(C)] 796 pub struct #lower<#lower_payload_generic_params> { 797 tag: wasmtime::ValRaw, 798 payload: #lower_payload<#lower_payload_generic_args> 799 } 800 801 #[doc(hidden)] 802 #[allow(non_snake_case)] 803 #[derive(Clone, Copy)] 804 #[repr(C)] 805 union #lower_payload<#lower_payload_generic_params> { 806 #lower_payload_case_declarations 807 } 808 809 unsafe impl #impl_generics wasmtime::component::ComponentType for #name #ty_generics #where_clause { 810 type Lower = #lower<#lower_generic_args>; 811 812 #[inline] 813 fn typecheck( 814 ty: &#internal::InterfaceType, 815 types: &#internal::ComponentTypes, 816 ) -> #internal::anyhow::Result<()> { 817 #internal::#typecheck(ty, types, &[#case_names_and_checks]) 818 } 819 820 const ABI: #internal::CanonicalAbiInfo = 821 #internal::CanonicalAbiInfo::variant_static(&[#abi_list]); 822 } 823 824 unsafe impl #impl_generics #internal::ComponentVariant for #name #ty_generics #where_clause { 825 const CASES: &'static [Option<#internal::CanonicalAbiInfo>] = &[#abi_list]; 826 } 827 }; 828 829 Ok(quote!(const _: () = { #expanded };)) 830 } 831 } 832 833 #[derive(Debug)] 834 struct Flag { 835 rename: Option<String>, 836 name: String, 837 } 838 839 impl Parse for Flag { 840 fn parse(input: ParseStream) -> Result<Self> { 841 let attributes = syn::Attribute::parse_outer(input)?; 842 843 let rename = find_rename(&attributes)? 844 .map(|literal| { 845 let s = literal.to_string(); 846 847 s.strip_prefix('"') 848 .and_then(|s| s.strip_suffix('"')) 849 .map(|s| s.to_owned()) 850 .ok_or_else(|| Error::new(literal.span(), "expected string literal")) 851 }) 852 .transpose()?; 853 854 input.parse::<Token![const]>()?; 855 let name = input.parse::<syn::Ident>()?.to_string(); 856 857 Ok(Self { rename, name }) 858 } 859 } 860 861 #[derive(Debug)] 862 pub struct Flags { 863 name: String, 864 flags: Vec<Flag>, 865 } 866 867 impl Parse for Flags { 868 fn parse(input: ParseStream) -> Result<Self> { 869 let name = input.parse::<syn::Ident>()?.to_string(); 870 871 let content; 872 braced!(content in input); 873 874 let flags = content 875 .parse_terminated::<_, Token![;]>(Flag::parse)? 876 .into_iter() 877 .collect(); 878 879 Ok(Self { name, flags }) 880 } 881 } 882 883 pub fn expand_flags(flags: &Flags) -> Result<TokenStream> { 884 let size = FlagsSize::from_count(flags.flags.len()); 885 886 let ty; 887 let eq; 888 889 let count = flags.flags.len(); 890 891 match size { 892 FlagsSize::Size0 => { 893 ty = quote!(()); 894 eq = quote!(true); 895 } 896 FlagsSize::Size1 => { 897 ty = quote!(u8); 898 899 eq = if count == 8 { 900 quote!(self.__inner0.eq(&rhs.__inner0)) 901 } else { 902 let mask = !(0xFF_u8 << count); 903 904 quote!((self.__inner0 & #mask).eq(&(rhs.__inner0 & #mask))) 905 }; 906 } 907 FlagsSize::Size2 => { 908 ty = quote!(u16); 909 910 eq = if count == 16 { 911 quote!(self.__inner0.eq(&rhs.__inner0)) 912 } else { 913 let mask = !(0xFFFF_u16 << count); 914 915 quote!((self.__inner0 & #mask).eq(&(rhs.__inner0 & #mask))) 916 }; 917 } 918 FlagsSize::Size4Plus(n) => { 919 ty = quote!(u32); 920 921 let comparisons = (0..(n - 1)) 922 .map(|index| { 923 let field = format_ident!("__inner{}", index); 924 925 quote!(self.#field.eq(&rhs.#field) &&) 926 }) 927 .collect::<TokenStream>(); 928 929 let field = format_ident!("__inner{}", n - 1); 930 931 eq = if count % 32 == 0 { 932 quote!(#comparisons self.#field.eq(&rhs.#field)) 933 } else { 934 let mask = !(0xFFFF_FFFF_u32 << (count % 32)); 935 936 quote!(#comparisons (self.#field & #mask).eq(&(rhs.#field & #mask))) 937 } 938 } 939 } 940 941 let count; 942 let mut as_array; 943 let mut bitor; 944 let mut bitor_assign; 945 let mut bitand; 946 let mut bitand_assign; 947 let mut bitxor; 948 let mut bitxor_assign; 949 let mut not; 950 951 match size { 952 FlagsSize::Size0 => { 953 count = 0; 954 as_array = quote!([]); 955 bitor = quote!(Self {}); 956 bitor_assign = quote!(); 957 bitand = quote!(Self {}); 958 bitand_assign = quote!(); 959 bitxor = quote!(Self {}); 960 bitxor_assign = quote!(); 961 not = quote!(Self {}); 962 } 963 FlagsSize::Size1 | FlagsSize::Size2 => { 964 count = 1; 965 as_array = quote!([self.__inner0 as u32]); 966 bitor = quote!(Self { 967 __inner0: self.__inner0.bitor(rhs.__inner0) 968 }); 969 bitor_assign = quote!(self.__inner0.bitor_assign(rhs.__inner0)); 970 bitand = quote!(Self { 971 __inner0: self.__inner0.bitand(rhs.__inner0) 972 }); 973 bitand_assign = quote!(self.__inner0.bitand_assign(rhs.__inner0)); 974 bitxor = quote!(Self { 975 __inner0: self.__inner0.bitxor(rhs.__inner0) 976 }); 977 bitxor_assign = quote!(self.__inner0.bitxor_assign(rhs.__inner0)); 978 not = quote!(Self { 979 __inner0: self.__inner0.not() 980 }); 981 } 982 FlagsSize::Size4Plus(n) => { 983 count = usize::from(n); 984 as_array = TokenStream::new(); 985 bitor = TokenStream::new(); 986 bitor_assign = TokenStream::new(); 987 bitand = TokenStream::new(); 988 bitand_assign = TokenStream::new(); 989 bitxor = TokenStream::new(); 990 bitxor_assign = TokenStream::new(); 991 not = TokenStream::new(); 992 993 for index in 0..n { 994 let field = format_ident!("__inner{}", index); 995 996 as_array.extend(quote!(self.#field,)); 997 bitor.extend(quote!(#field: self.#field.bitor(rhs.#field),)); 998 bitor_assign.extend(quote!(self.#field.bitor_assign(rhs.#field);)); 999 bitand.extend(quote!(#field: self.#field.bitand(rhs.#field),)); 1000 bitand_assign.extend(quote!(self.#field.bitand_assign(rhs.#field);)); 1001 bitxor.extend(quote!(#field: self.#field.bitxor(rhs.#field),)); 1002 bitxor_assign.extend(quote!(self.#field.bitxor_assign(rhs.#field);)); 1003 not.extend(quote!(#field: self.#field.not(),)); 1004 } 1005 1006 as_array = quote!([#as_array]); 1007 bitor = quote!(Self { #bitor }); 1008 bitand = quote!(Self { #bitand }); 1009 bitxor = quote!(Self { #bitxor }); 1010 not = quote!(Self { #not }); 1011 } 1012 }; 1013 1014 let name = format_ident!("{}", flags.name); 1015 1016 let mut constants = TokenStream::new(); 1017 let mut rust_names = TokenStream::new(); 1018 let mut component_names = TokenStream::new(); 1019 1020 for (index, Flag { name, rename }) in flags.flags.iter().enumerate() { 1021 rust_names.extend(quote!(#name,)); 1022 1023 let component_name = rename.as_ref().unwrap_or(name); 1024 component_names.extend(quote!(#component_name,)); 1025 1026 let fields = match size { 1027 FlagsSize::Size0 => quote!(), 1028 FlagsSize::Size1 => { 1029 let init = 1_u8 << index; 1030 quote!(__inner0: #init) 1031 } 1032 FlagsSize::Size2 => { 1033 let init = 1_u16 << index; 1034 quote!(__inner0: #init) 1035 } 1036 FlagsSize::Size4Plus(n) => (0..n) 1037 .map(|i| { 1038 let field = format_ident!("__inner{}", i); 1039 1040 let init = if index / 32 == usize::from(i) { 1041 1_u32 << (index % 32) 1042 } else { 1043 0 1044 }; 1045 1046 quote!(#field: #init,) 1047 }) 1048 .collect::<TokenStream>(), 1049 }; 1050 1051 let name = format_ident!("{}", name); 1052 1053 constants.extend(quote!(pub const #name: Self = Self { #fields };)); 1054 } 1055 1056 let generics = syn::Generics { 1057 lt_token: None, 1058 params: Punctuated::new(), 1059 gt_token: None, 1060 where_clause: None, 1061 }; 1062 1063 let fields = { 1064 let ty = syn::parse2::<syn::Type>(ty.clone())?; 1065 1066 (0..count) 1067 .map(|index| syn::Field { 1068 attrs: Vec::new(), 1069 vis: syn::Visibility::Inherited, 1070 ident: Some(format_ident!("__inner{}", index)), 1071 colon_token: None, 1072 ty: ty.clone(), 1073 }) 1074 .collect::<Vec<_>>() 1075 }; 1076 1077 let fields = fields.iter().collect::<Vec<_>>(); 1078 1079 let component_type_impl = expand_record_for_component_type( 1080 &name, 1081 &generics, 1082 &fields, 1083 quote!(typecheck_flags), 1084 component_names, 1085 )?; 1086 1087 let lower_impl = LowerExpander.expand_record(&name, &generics, &fields)?; 1088 1089 let lift_impl = LiftExpander.expand_record(&name, &generics, &fields)?; 1090 1091 let internal = quote!(wasmtime::component::__internal); 1092 1093 let fields = fields 1094 .iter() 1095 .map(|syn::Field { ident, .. }| quote!(#[doc(hidden)] #ident: #ty,)) 1096 .collect::<TokenStream>(); 1097 1098 let expanded = quote! { 1099 #[derive(Copy, Clone, Default)] 1100 pub struct #name { #fields } 1101 1102 impl #name { 1103 #constants 1104 1105 pub fn as_array(&self) -> [u32; #count] { 1106 #as_array 1107 } 1108 1109 pub fn empty() -> Self { 1110 Self::default() 1111 } 1112 1113 pub fn all() -> Self { 1114 use std::ops::Not; 1115 Self::default().not() 1116 } 1117 } 1118 1119 impl std::cmp::PartialEq for #name { 1120 fn eq(&self, rhs: &#name) -> bool { 1121 #eq 1122 } 1123 } 1124 1125 impl std::cmp::Eq for #name { } 1126 1127 impl std::fmt::Debug for #name { 1128 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 1129 #internal::format_flags(&self.as_array(), &[#rust_names], f) 1130 } 1131 } 1132 1133 impl std::ops::BitOr for #name { 1134 type Output = #name; 1135 1136 fn bitor(self, rhs: #name) -> #name { 1137 #bitor 1138 } 1139 } 1140 1141 impl std::ops::BitOrAssign for #name { 1142 fn bitor_assign(&mut self, rhs: #name) { 1143 #bitor_assign 1144 } 1145 } 1146 1147 impl std::ops::BitAnd for #name { 1148 type Output = #name; 1149 1150 fn bitand(self, rhs: #name) -> #name { 1151 #bitand 1152 } 1153 } 1154 1155 impl std::ops::BitAndAssign for #name { 1156 fn bitand_assign(&mut self, rhs: #name) { 1157 #bitand_assign 1158 } 1159 } 1160 1161 impl std::ops::BitXor for #name { 1162 type Output = #name; 1163 1164 fn bitxor(self, rhs: #name) -> #name { 1165 #bitxor 1166 } 1167 } 1168 1169 impl std::ops::BitXorAssign for #name { 1170 fn bitxor_assign(&mut self, rhs: #name) { 1171 #bitxor_assign 1172 } 1173 } 1174 1175 impl std::ops::Not for #name { 1176 type Output = #name; 1177 1178 fn not(self) -> #name { 1179 #not 1180 } 1181 } 1182 1183 #component_type_impl 1184 1185 #lower_impl 1186 1187 #lift_impl 1188 }; 1189 1190 Ok(expanded) 1191 } 1192