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_macro_input, parse_quote, Data, DeriveInput, Error, Result, Token}; 8 use wasmtime_component_util::{DiscriminantSize, FlagsSize}; 9 10 #[derive(Debug, Copy, Clone)] 11 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 struct VariantCase<'a> { 152 attrs: &'a [syn::Attribute], 153 ident: &'a syn::Ident, 154 ty: Option<&'a syn::Type>, 155 } 156 157 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 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 #[proc_macro_derive(Lift, attributes(component))] 384 pub fn lift(input: proc_macro::TokenStream) -> proc_macro::TokenStream { 385 expand(&LiftExpander, &parse_macro_input!(input as DeriveInput)) 386 .unwrap_or_else(Error::into_compile_error) 387 .into() 388 } 389 390 struct LiftExpander; 391 392 impl Expander for LiftExpander { 393 fn expand_record( 394 &self, 395 name: &syn::Ident, 396 generics: &syn::Generics, 397 fields: &[&syn::Field], 398 ) -> Result<TokenStream> { 399 let internal = quote!(wasmtime::component::__internal); 400 401 let mut lifts = TokenStream::new(); 402 let mut loads = TokenStream::new(); 403 404 for syn::Field { ident, ty, .. } in fields { 405 lifts.extend(quote!(#ident: <#ty as wasmtime::component::Lift>::lift( 406 store, options, &src.#ident 407 )?,)); 408 409 loads.extend(quote!(#ident: <#ty as wasmtime::component::Lift>::load( 410 memory, 411 &bytes 412 [<#ty as wasmtime::component::ComponentType>::ABI.next_field32_size(&mut offset)..] 413 [..<#ty as wasmtime::component::ComponentType>::SIZE32] 414 )?,)); 415 } 416 417 let generics = add_trait_bounds(generics, parse_quote!(wasmtime::component::Lift)); 418 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 419 420 let expanded = quote! { 421 unsafe impl #impl_generics wasmtime::component::Lift for #name #ty_generics #where_clause { 422 #[inline] 423 fn lift( 424 store: &#internal::StoreOpaque, 425 options: &#internal::Options, 426 src: &Self::Lower, 427 ) -> #internal::anyhow::Result<Self> { 428 Ok(Self { 429 #lifts 430 }) 431 } 432 433 #[inline] 434 fn load(memory: &#internal::Memory, bytes: &[u8]) -> #internal::anyhow::Result<Self> { 435 debug_assert!( 436 (bytes.as_ptr() as usize) 437 % (<Self as wasmtime::component::ComponentType>::ALIGN32 as usize) 438 == 0 439 ); 440 let mut offset = 0; 441 Ok(Self { 442 #loads 443 }) 444 } 445 } 446 }; 447 448 Ok(expanded) 449 } 450 451 fn expand_variant( 452 &self, 453 name: &syn::Ident, 454 generics: &syn::Generics, 455 discriminant_size: DiscriminantSize, 456 cases: &[VariantCase], 457 _style: VariantStyle, 458 ) -> Result<TokenStream> { 459 let internal = quote!(wasmtime::component::__internal); 460 461 let mut lifts = TokenStream::new(); 462 let mut loads = TokenStream::new(); 463 464 for (index, VariantCase { ident, ty, .. }) in cases.iter().enumerate() { 465 let index_u32 = u32::try_from(index).unwrap(); 466 467 let index_quoted = quote(discriminant_size, index); 468 469 if let Some(ty) = ty { 470 lifts.extend( 471 quote!(#index_u32 => Self::#ident(<#ty as wasmtime::component::Lift>::lift( 472 store, options, unsafe { &src.payload.#ident } 473 )?),), 474 ); 475 476 loads.extend( 477 quote!(#index_quoted => Self::#ident(<#ty as wasmtime::component::Lift>::load( 478 memory, &payload[..<#ty as wasmtime::component::ComponentType>::SIZE32] 479 )?),), 480 ); 481 } else { 482 lifts.extend(quote!(#index_u32 => Self::#ident,)); 483 484 loads.extend(quote!(#index_quoted => Self::#ident,)); 485 } 486 } 487 488 let generics = add_trait_bounds(generics, parse_quote!(wasmtime::component::Lift)); 489 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 490 491 let from_bytes = match discriminant_size { 492 DiscriminantSize::Size1 => quote!(bytes[0]), 493 DiscriminantSize::Size2 => quote!(u16::from_le_bytes(bytes[0..2].try_into()?)), 494 DiscriminantSize::Size4 => quote!(u32::from_le_bytes(bytes[0..4].try_into()?)), 495 }; 496 497 let expanded = quote! { 498 unsafe impl #impl_generics wasmtime::component::Lift for #name #ty_generics #where_clause { 499 #[inline] 500 fn lift( 501 store: &#internal::StoreOpaque, 502 options: &#internal::Options, 503 src: &Self::Lower, 504 ) -> #internal::anyhow::Result<Self> { 505 Ok(match src.tag.get_u32() { 506 #lifts 507 discrim => #internal::anyhow::bail!("unexpected discriminant: {}", discrim), 508 }) 509 } 510 511 #[inline] 512 fn load(memory: &#internal::Memory, bytes: &[u8]) -> #internal::anyhow::Result<Self> { 513 let align = <Self as wasmtime::component::ComponentType>::ALIGN32; 514 debug_assert!((bytes.as_ptr() as usize) % (align as usize) == 0); 515 let discrim = #from_bytes; 516 let payload_offset = <Self as #internal::ComponentVariant>::PAYLOAD_OFFSET32; 517 let payload = &bytes[payload_offset..]; 518 Ok(match discrim { 519 #loads 520 discrim => #internal::anyhow::bail!("unexpected discriminant: {}", discrim), 521 }) 522 } 523 } 524 }; 525 526 Ok(expanded) 527 } 528 } 529 530 #[proc_macro_derive(Lower, attributes(component))] 531 pub fn lower(input: proc_macro::TokenStream) -> proc_macro::TokenStream { 532 expand(&LowerExpander, &parse_macro_input!(input as DeriveInput)) 533 .unwrap_or_else(Error::into_compile_error) 534 .into() 535 } 536 537 struct LowerExpander; 538 539 impl Expander for LowerExpander { 540 fn expand_record( 541 &self, 542 name: &syn::Ident, 543 generics: &syn::Generics, 544 fields: &[&syn::Field], 545 ) -> Result<TokenStream> { 546 let internal = quote!(wasmtime::component::__internal); 547 548 let mut lowers = TokenStream::new(); 549 let mut stores = TokenStream::new(); 550 551 for syn::Field { ident, ty, .. } in fields { 552 lowers.extend(quote!(wasmtime::component::Lower::lower( 553 &self.#ident, store, options, #internal::map_maybe_uninit!(dst.#ident) 554 )?;)); 555 556 stores.extend(quote!(wasmtime::component::Lower::store( 557 &self.#ident, 558 memory, 559 <#ty as wasmtime::component::ComponentType>::ABI.next_field32_size(&mut offset), 560 )?;)); 561 } 562 563 let generics = add_trait_bounds(generics, parse_quote!(wasmtime::component::Lower)); 564 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 565 566 let expanded = quote! { 567 unsafe impl #impl_generics wasmtime::component::Lower for #name #ty_generics #where_clause { 568 #[inline] 569 fn lower<T>( 570 &self, 571 store: &mut wasmtime::StoreContextMut<T>, 572 options: &#internal::Options, 573 dst: &mut std::mem::MaybeUninit<Self::Lower>, 574 ) -> #internal::anyhow::Result<()> { 575 #lowers 576 Ok(()) 577 } 578 579 #[inline] 580 fn store<T>( 581 &self, 582 memory: &mut #internal::MemoryMut<'_, T>, 583 mut offset: usize 584 ) -> #internal::anyhow::Result<()> { 585 debug_assert!(offset % (<Self as wasmtime::component::ComponentType>::ALIGN32 as usize) == 0); 586 #stores 587 Ok(()) 588 } 589 } 590 }; 591 592 Ok(expanded) 593 } 594 595 fn expand_variant( 596 &self, 597 name: &syn::Ident, 598 generics: &syn::Generics, 599 discriminant_size: DiscriminantSize, 600 cases: &[VariantCase], 601 _style: VariantStyle, 602 ) -> Result<TokenStream> { 603 let internal = quote!(wasmtime::component::__internal); 604 605 let mut lowers = TokenStream::new(); 606 let mut stores = TokenStream::new(); 607 608 for (index, VariantCase { ident, ty, .. }) in cases.iter().enumerate() { 609 let index_u32 = u32::try_from(index).unwrap(); 610 611 let index_quoted = quote(discriminant_size, index); 612 613 let discriminant_size = usize::from(discriminant_size); 614 615 let pattern; 616 let lower; 617 let store; 618 619 if ty.is_some() { 620 pattern = quote!(Self::#ident(value)); 621 lower = quote!(value.lower(store, options, #internal::map_maybe_uninit!(dst.payload.#ident))); 622 store = quote!(value.store( 623 memory, 624 offset + <Self as #internal::ComponentVariant>::PAYLOAD_OFFSET32, 625 )); 626 } else { 627 pattern = quote!(Self::#ident); 628 lower = quote!(Ok(())); 629 store = quote!(Ok(())); 630 } 631 632 lowers.extend(quote!(#pattern => { 633 #internal::map_maybe_uninit!(dst.tag).write(wasmtime::ValRaw::i32(#index_u32 as i32)); 634 #lower 635 })); 636 637 stores.extend(quote!(#pattern => { 638 *memory.get::<#discriminant_size>(offset) = #index_quoted.to_le_bytes(); 639 #store 640 })); 641 } 642 643 let generics = add_trait_bounds(generics, parse_quote!(wasmtime::component::Lower)); 644 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 645 646 let expanded = quote! { 647 unsafe impl #impl_generics wasmtime::component::Lower for #name #ty_generics #where_clause { 648 #[inline] 649 fn lower<T>( 650 &self, 651 store: &mut wasmtime::StoreContextMut<T>, 652 options: &#internal::Options, 653 dst: &mut std::mem::MaybeUninit<Self::Lower>, 654 ) -> #internal::anyhow::Result<()> { 655 // See comment in <Result<T, E> as Lower>::lower for why we zero out the payload here 656 unsafe { 657 #internal::map_maybe_uninit!(dst.payload) 658 .as_mut_ptr() 659 .write_bytes(0u8, 1); 660 } 661 662 match self { 663 #lowers 664 } 665 } 666 667 #[inline] 668 fn store<T>( 669 &self, 670 memory: &mut #internal::MemoryMut<'_, T>, 671 mut offset: usize 672 ) -> #internal::anyhow::Result<()> { 673 debug_assert!(offset % (<Self as wasmtime::component::ComponentType>::ALIGN32 as usize) == 0); 674 match self { 675 #stores 676 } 677 } 678 } 679 }; 680 681 Ok(expanded) 682 } 683 } 684 685 #[proc_macro_derive(ComponentType, attributes(component))] 686 pub fn component_type(input: proc_macro::TokenStream) -> proc_macro::TokenStream { 687 expand( 688 &ComponentTypeExpander, 689 &parse_macro_input!(input as DeriveInput), 690 ) 691 .unwrap_or_else(Error::into_compile_error) 692 .into() 693 } 694 695 struct ComponentTypeExpander; 696 697 impl Expander for ComponentTypeExpander { 698 fn expand_record( 699 &self, 700 name: &syn::Ident, 701 generics: &syn::Generics, 702 fields: &[&syn::Field], 703 ) -> Result<TokenStream> { 704 expand_record_for_component_type( 705 name, 706 generics, 707 fields, 708 quote!(typecheck_record), 709 fields 710 .iter() 711 .map( 712 |syn::Field { 713 attrs, ident, ty, .. 714 }| { 715 let name = find_rename(attrs)?.unwrap_or_else(|| { 716 Literal::string(&ident.as_ref().unwrap().to_string()) 717 }); 718 719 Ok(quote!((#name, <#ty as wasmtime::component::ComponentType>::typecheck),)) 720 }, 721 ) 722 .collect::<Result<_>>()?, 723 ) 724 } 725 726 fn expand_variant( 727 &self, 728 name: &syn::Ident, 729 generics: &syn::Generics, 730 _discriminant_size: DiscriminantSize, 731 cases: &[VariantCase], 732 style: VariantStyle, 733 ) -> Result<TokenStream> { 734 let internal = quote!(wasmtime::component::__internal); 735 736 let mut case_names_and_checks = TokenStream::new(); 737 let mut lower_payload_generic_params = TokenStream::new(); 738 let mut lower_payload_generic_args = TokenStream::new(); 739 let mut lower_payload_case_declarations = TokenStream::new(); 740 let mut lower_generic_args = TokenStream::new(); 741 let mut abi_list = TokenStream::new(); 742 let mut unique_types = HashSet::new(); 743 744 for (index, VariantCase { attrs, ident, ty }) in cases.iter().enumerate() { 745 let rename = find_rename(attrs)?; 746 747 if let (Some(_), VariantStyle::Union) = (&rename, style) { 748 return Err(Error::new( 749 ident.span(), 750 "renaming `union` cases is not permitted; only the type is used", 751 )); 752 } 753 754 let name = rename.unwrap_or_else(|| Literal::string(&ident.to_string())); 755 756 if let Some(ty) = ty { 757 abi_list.extend(quote!(<#ty as wasmtime::component::ComponentType>::ABI,)); 758 759 case_names_and_checks.extend(match style { 760 VariantStyle::Variant => { 761 quote!((#name, <#ty as wasmtime::component::ComponentType>::typecheck),) 762 } 763 VariantStyle::Union => { 764 quote!(<#ty as wasmtime::component::ComponentType>::typecheck,) 765 } 766 VariantStyle::Enum => { 767 return Err(Error::new( 768 ident.span(), 769 "payloads are not permitted for `enum` cases", 770 )) 771 } 772 }); 773 774 let generic = format_ident!("T{}", index); 775 776 lower_payload_generic_params.extend(quote!(#generic: Copy,)); 777 lower_payload_generic_args.extend(quote!(#generic,)); 778 lower_payload_case_declarations.extend(quote!(#ident: #generic,)); 779 lower_generic_args 780 .extend(quote!(<#ty as wasmtime::component::ComponentType>::Lower,)); 781 782 unique_types.insert(ty); 783 } else { 784 abi_list.extend(quote!(<() as wasmtime::component::ComponentType>::ABI,)); 785 case_names_and_checks.extend(match style { 786 VariantStyle::Variant => { 787 quote!((#name, <() as wasmtime::component::ComponentType>::typecheck),) 788 } 789 VariantStyle::Union => { 790 quote!(<() as wasmtime::component::ComponentType>::typecheck,) 791 } 792 VariantStyle::Enum => quote!(#name,), 793 }); 794 } 795 } 796 797 if lower_payload_case_declarations.is_empty() { 798 lower_payload_case_declarations.extend(quote!(_dummy: ())); 799 } 800 801 let typecheck = match style { 802 VariantStyle::Variant => quote!(typecheck_variant), 803 VariantStyle::Union => quote!(typecheck_union), 804 VariantStyle::Enum => quote!(typecheck_enum), 805 }; 806 807 let generics = add_trait_bounds(generics, parse_quote!(wasmtime::component::ComponentType)); 808 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 809 let lower = format_ident!("Lower{}", name); 810 let lower_payload = format_ident!("LowerPayload{}", name); 811 812 // You may wonder why we make the types of all the fields of the #lower struct and #lower_payload union 813 // generic. This is to work around a [normalization bug in 814 // rustc](https://github.com/rust-lang/rust/issues/90903) such that the compiler does not understand that 815 // e.g. `<i32 as ComponentType>::Lower` is `Copy` despite the bound specified in `ComponentType`'s 816 // definition. 817 // 818 // See also the comment in `Self::expand_record` above for another reason why we do this. 819 820 let expanded = quote! { 821 #[doc(hidden)] 822 #[derive(Clone, Copy)] 823 #[repr(C)] 824 pub struct #lower<#lower_payload_generic_params> { 825 tag: wasmtime::ValRaw, 826 payload: #lower_payload<#lower_payload_generic_args> 827 } 828 829 #[doc(hidden)] 830 #[allow(non_snake_case)] 831 #[derive(Clone, Copy)] 832 #[repr(C)] 833 union #lower_payload<#lower_payload_generic_params> { 834 #lower_payload_case_declarations 835 } 836 837 unsafe impl #impl_generics wasmtime::component::ComponentType for #name #ty_generics #where_clause { 838 type Lower = #lower<#lower_generic_args>; 839 840 #[inline] 841 fn typecheck( 842 ty: &#internal::InterfaceType, 843 types: &#internal::ComponentTypes, 844 ) -> #internal::anyhow::Result<()> { 845 #internal::#typecheck(ty, types, &[#case_names_and_checks]) 846 } 847 848 const ABI: #internal::CanonicalAbiInfo = 849 #internal::CanonicalAbiInfo::variant_static(&[#abi_list]); 850 } 851 852 unsafe impl #impl_generics #internal::ComponentVariant for #name #ty_generics #where_clause { 853 const CASES: &'static [#internal::CanonicalAbiInfo] = &[#abi_list]; 854 } 855 }; 856 857 Ok(quote!(const _: () = { #expanded };)) 858 } 859 } 860 861 #[derive(Debug)] 862 struct Flag { 863 rename: Option<String>, 864 name: String, 865 } 866 867 impl Parse for Flag { 868 fn parse(input: ParseStream) -> Result<Self> { 869 let attributes = syn::Attribute::parse_outer(input)?; 870 871 let rename = find_rename(&attributes)? 872 .map(|literal| { 873 let s = literal.to_string(); 874 875 s.strip_prefix('"') 876 .and_then(|s| s.strip_suffix('"')) 877 .map(|s| s.to_owned()) 878 .ok_or_else(|| Error::new(literal.span(), "expected string literal")) 879 }) 880 .transpose()?; 881 882 input.parse::<Token![const]>()?; 883 let name = input.parse::<syn::Ident>()?.to_string(); 884 885 Ok(Self { rename, name }) 886 } 887 } 888 889 #[derive(Debug)] 890 struct Flags { 891 name: String, 892 flags: Vec<Flag>, 893 } 894 895 impl Parse for Flags { 896 fn parse(input: ParseStream) -> Result<Self> { 897 let name = input.parse::<syn::Ident>()?.to_string(); 898 899 let content; 900 braced!(content in input); 901 902 let flags = content 903 .parse_terminated::<_, Token![;]>(Flag::parse)? 904 .into_iter() 905 .collect(); 906 907 Ok(Self { name, flags }) 908 } 909 } 910 911 #[proc_macro] 912 pub fn flags(input: proc_macro::TokenStream) -> proc_macro::TokenStream { 913 expand_flags(&parse_macro_input!(input as Flags)) 914 .unwrap_or_else(Error::into_compile_error) 915 .into() 916 } 917 918 fn expand_flags(flags: &Flags) -> Result<TokenStream> { 919 let size = FlagsSize::from_count(flags.flags.len()); 920 921 let ty; 922 let eq; 923 924 let count = flags.flags.len(); 925 926 match size { 927 FlagsSize::Size0 => { 928 ty = quote!(()); 929 eq = quote!(true); 930 } 931 FlagsSize::Size1 => { 932 ty = quote!(u8); 933 934 eq = if count == 8 { 935 quote!(self.__inner0.eq(&rhs.__inner0)) 936 } else { 937 let mask = !(0xFF_u8 << count); 938 939 quote!((self.__inner0 & #mask).eq(&(rhs.__inner0 & #mask))) 940 }; 941 } 942 FlagsSize::Size2 => { 943 ty = quote!(u16); 944 945 eq = if count == 16 { 946 quote!(self.__inner0.eq(&rhs.__inner0)) 947 } else { 948 let mask = !(0xFFFF_u16 << count); 949 950 quote!((self.__inner0 & #mask).eq(&(rhs.__inner0 & #mask))) 951 }; 952 } 953 FlagsSize::Size4Plus(n) => { 954 ty = quote!(u32); 955 956 let comparisons = (0..(n - 1)) 957 .map(|index| { 958 let field = format_ident!("__inner{}", index); 959 960 quote!(self.#field.eq(&rhs.#field) &&) 961 }) 962 .collect::<TokenStream>(); 963 964 let field = format_ident!("__inner{}", n - 1); 965 966 eq = if count % 32 == 0 { 967 quote!(#comparisons self.#field.eq(&rhs.#field)) 968 } else { 969 let mask = !(0xFFFF_FFFF_u32 << (count % 32)); 970 971 quote!(#comparisons (self.#field & #mask).eq(&(rhs.#field & #mask))) 972 } 973 } 974 } 975 976 let count; 977 let mut as_array; 978 let mut bitor; 979 let mut bitor_assign; 980 let mut bitand; 981 let mut bitand_assign; 982 let mut bitxor; 983 let mut bitxor_assign; 984 let mut not; 985 986 match size { 987 FlagsSize::Size0 => { 988 count = 0; 989 as_array = quote!([]); 990 bitor = quote!(Self {}); 991 bitor_assign = quote!(); 992 bitand = quote!(Self {}); 993 bitand_assign = quote!(); 994 bitxor = quote!(Self {}); 995 bitxor_assign = quote!(); 996 not = quote!(Self {}); 997 } 998 FlagsSize::Size1 | FlagsSize::Size2 => { 999 count = 1; 1000 as_array = quote!([self.__inner0 as u32]); 1001 bitor = quote!(Self { 1002 __inner0: self.__inner0.bitor(rhs.__inner0) 1003 }); 1004 bitor_assign = quote!(self.__inner0.bitor_assign(rhs.__inner0)); 1005 bitand = quote!(Self { 1006 __inner0: self.__inner0.bitand(rhs.__inner0) 1007 }); 1008 bitand_assign = quote!(self.__inner0.bitand_assign(rhs.__inner0)); 1009 bitxor = quote!(Self { 1010 __inner0: self.__inner0.bitxor(rhs.__inner0) 1011 }); 1012 bitxor_assign = quote!(self.__inner0.bitxor_assign(rhs.__inner0)); 1013 not = quote!(Self { 1014 __inner0: self.__inner0.not() 1015 }); 1016 } 1017 FlagsSize::Size4Plus(n) => { 1018 count = n; 1019 as_array = TokenStream::new(); 1020 bitor = TokenStream::new(); 1021 bitor_assign = TokenStream::new(); 1022 bitand = TokenStream::new(); 1023 bitand_assign = TokenStream::new(); 1024 bitxor = TokenStream::new(); 1025 bitxor_assign = TokenStream::new(); 1026 not = TokenStream::new(); 1027 1028 for index in 0..n { 1029 let field = format_ident!("__inner{}", index); 1030 1031 as_array.extend(quote!(self.#field,)); 1032 bitor.extend(quote!(#field: self.#field.bitor(rhs.#field),)); 1033 bitor_assign.extend(quote!(self.#field.bitor_assign(rhs.#field);)); 1034 bitand.extend(quote!(#field: self.#field.bitand(rhs.#field),)); 1035 bitand_assign.extend(quote!(self.#field.bitand_assign(rhs.#field);)); 1036 bitxor.extend(quote!(#field: self.#field.bitxor(rhs.#field),)); 1037 bitxor_assign.extend(quote!(self.#field.bitxor_assign(rhs.#field);)); 1038 not.extend(quote!(#field: self.#field.not(),)); 1039 } 1040 1041 as_array = quote!([#as_array]); 1042 bitor = quote!(Self { #bitor }); 1043 bitand = quote!(Self { #bitand }); 1044 bitxor = quote!(Self { #bitxor }); 1045 not = quote!(Self { #not }); 1046 } 1047 }; 1048 1049 let name = format_ident!("{}", flags.name); 1050 1051 let mut constants = TokenStream::new(); 1052 let mut rust_names = TokenStream::new(); 1053 let mut component_names = TokenStream::new(); 1054 1055 for (index, Flag { name, rename }) in flags.flags.iter().enumerate() { 1056 rust_names.extend(quote!(#name,)); 1057 1058 let component_name = rename.as_ref().unwrap_or(name); 1059 component_names.extend(quote!(#component_name,)); 1060 1061 let fields = match size { 1062 FlagsSize::Size0 => quote!(), 1063 FlagsSize::Size1 => { 1064 let init = 1_u8 << index; 1065 quote!(__inner0: #init) 1066 } 1067 FlagsSize::Size2 => { 1068 let init = 1_u16 << index; 1069 quote!(__inner0: #init) 1070 } 1071 FlagsSize::Size4Plus(n) => (0..n) 1072 .map(|i| { 1073 let field = format_ident!("__inner{}", i); 1074 1075 let init = if index / 32 == i { 1076 1_u32 << (index % 32) 1077 } else { 1078 0 1079 }; 1080 1081 quote!(#field: #init,) 1082 }) 1083 .collect::<TokenStream>(), 1084 }; 1085 1086 let name = format_ident!("{}", name); 1087 1088 constants.extend(quote!(const #name: Self = Self { #fields };)); 1089 } 1090 1091 let generics = syn::Generics { 1092 lt_token: None, 1093 params: Punctuated::new(), 1094 gt_token: None, 1095 where_clause: None, 1096 }; 1097 1098 let fields = { 1099 let ty = syn::parse2::<syn::Type>(ty.clone())?; 1100 1101 (0..count) 1102 .map(|index| syn::Field { 1103 attrs: Vec::new(), 1104 vis: syn::Visibility::Inherited, 1105 ident: Some(format_ident!("__inner{}", index)), 1106 colon_token: None, 1107 ty: ty.clone(), 1108 }) 1109 .collect::<Vec<_>>() 1110 }; 1111 1112 let fields = fields.iter().collect::<Vec<_>>(); 1113 1114 let component_type_impl = expand_record_for_component_type( 1115 &name, 1116 &generics, 1117 &fields, 1118 quote!(typecheck_flags), 1119 component_names, 1120 )?; 1121 1122 let lower_impl = LowerExpander.expand_record(&name, &generics, &fields)?; 1123 1124 let lift_impl = LiftExpander.expand_record(&name, &generics, &fields)?; 1125 1126 let internal = quote!(wasmtime::component::__internal); 1127 1128 let fields = fields 1129 .iter() 1130 .map(|syn::Field { ident, .. }| quote!(#[doc(hidden)] #ident: #ty,)) 1131 .collect::<TokenStream>(); 1132 1133 let expanded = quote! { 1134 #[derive(Copy, Clone, Default)] 1135 struct #name { #fields } 1136 1137 impl #name { 1138 #constants 1139 1140 fn as_array(&self) -> [u32; #count] { 1141 #as_array 1142 } 1143 } 1144 1145 impl std::cmp::PartialEq for #name { 1146 fn eq(&self, rhs: &#name) -> bool { 1147 #eq 1148 } 1149 } 1150 1151 impl std::cmp::Eq for #name { } 1152 1153 impl std::fmt::Debug for #name { 1154 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 1155 #internal::format_flags(&self.as_array(), &[#rust_names], f) 1156 } 1157 } 1158 1159 impl std::ops::BitOr for #name { 1160 type Output = #name; 1161 1162 fn bitor(self, rhs: #name) -> #name { 1163 #bitor 1164 } 1165 } 1166 1167 impl std::ops::BitOrAssign for #name { 1168 fn bitor_assign(&mut self, rhs: #name) { 1169 #bitor_assign 1170 } 1171 } 1172 1173 impl std::ops::BitAnd for #name { 1174 type Output = #name; 1175 1176 fn bitand(self, rhs: #name) -> #name { 1177 #bitand 1178 } 1179 } 1180 1181 impl std::ops::BitAndAssign for #name { 1182 fn bitand_assign(&mut self, rhs: #name) { 1183 #bitand_assign 1184 } 1185 } 1186 1187 impl std::ops::BitXor for #name { 1188 type Output = #name; 1189 1190 fn bitxor(self, rhs: #name) -> #name { 1191 #bitxor 1192 } 1193 } 1194 1195 impl std::ops::BitXorAssign for #name { 1196 fn bitxor_assign(&mut self, rhs: #name) { 1197 #bitxor_assign 1198 } 1199 } 1200 1201 impl std::ops::Not for #name { 1202 type Output = #name; 1203 1204 fn not(self) -> #name { 1205 #not 1206 } 1207 } 1208 1209 #component_type_impl 1210 1211 #lower_impl 1212 1213 #lift_impl 1214 }; 1215 1216 Ok(expanded) 1217 } 1218