### Apply Send bounds to a trait using make Source: https://docs.rs/trait-variant/latest/trait_variant/attr.make.html Demonstrates applying Send bounds to async functions and iterator return types within a trait definition. ```rust #[trait_variant::make(Send)] trait IntFactory { async fn make(&self) -> i32; fn stream(&self) -> impl Iterator; fn call(&self) -> u32; } ``` -------------------------------- ### Generated trait structure Source: https://docs.rs/trait-variant/latest/trait_variant/attr.make.html Shows the resulting trait structure after the make macro processes the input trait. ```rust trait IntFactory: Send { fn make(&self) -> impl Future + Send; fn stream(&self) -> impl Iterator + Send; fn call(&self) -> u32; } ``` -------------------------------- ### Procedural Macro Implementation for Trait Variants Source: https://docs.rs/trait-variant/latest/src/trait_variant/variant.rs.html Defines the parsing logic and macro expansion for creating or rewriting traits with additional bounds. ```rust 1// Copyright (c) 2023 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 or the MIT license 5// , at your 6// option. This file may not be copied, modified, or distributed 7// except according to those terms. 8 9use std::iter; 10 11use proc_macro2::TokenStream; 12use quote::quote; 13use syn::{ 14 parse::{Parse, ParseStream}, 15 parse_macro_input, parse_quote, 16 punctuated::Punctuated, 17 token::Plus, 18 Error, FnArg, GenericParam, Ident, ItemTrait, Pat, PatType, Result, ReturnType, Signature, 19 Token, TraitBound, TraitItem, TraitItemConst, TraitItemFn, TraitItemType, Type, TypeGenerics, 20 TypeImplTrait, TypeParam, TypeParamBound, 21}; 22 23struct Attrs { 24 variant: MakeVariant, 25} 26 27impl Parse for Attrs { 28 fn parse(input: ParseStream) -> Result { 29 Ok(Self { 30 variant: MakeVariant::parse(input)?, 31 }) 32 } 33} 34 35enum MakeVariant { 36 // Creates a variant of a trait under a new name with additional bounds while preserving the original trait. 37 Create { 38 name: Ident, 39 _colon: Token![:], 40 bounds: Punctuated, 41 }, 42 // Rewrites the original trait into a new trait with additional bounds. 43 Rewrite { 44 bounds: Punctuated, 45 }, 46} 47 48impl Parse for MakeVariant { 49 fn parse(input: ParseStream) -> Result { 50 let variant = if input.peek(Ident) && input.peek2(Token![:]) { 51 MakeVariant::Create { 52 name: input.parse()?, 53 _colon: input.parse()?, 54 bounds: input.parse_terminated(TraitBound::parse, Token![+])?, 55 } 56 } else { 57 MakeVariant::Rewrite { 58 bounds: input.parse_terminated(TraitBound::parse, Token![+])?, 59 } 60 }; 61 Ok(variant) 62 } 63} 64 65pub fn make( 66 attr: proc_macro::TokenStream, 67 item: proc_macro::TokenStream, 68) -> proc_macro::TokenStream { 69 let attrs = parse_macro_input!(attr as Attrs); 70 let item = parse_macro_input!(item as ItemTrait); 71 72 match attrs.variant { 73 MakeVariant::Create { name, bounds, .. } => { 74 let maybe_allow_async_lint = if bounds 75 .iter() 76 .any(|b| b.path.segments.last().unwrap().ident == "Send") 77 { 78 quote! { #[allow(async_fn_in_trait)] } 79 } else { 80 quote! {} 81 }; 82 83 let variant = mk_variant(&name, bounds, &item); 84 let blanket_impl = mk_blanket_impl(&name, &item); 85 86 quote! { 87 #maybe_allow_async_lint 88 #item 89 90 #variant 91 92 #blanket_impl 93 } 94 .into() 95 } 96 MakeVariant::Rewrite { bounds, .. } => { 97 let variant = mk_variant(&item.ident, bounds, &item); 98 quote! { 99 #variant 100 } 101 .into() 102 } 103 } 104} 105 106fn mk_variant( 107 variant: &Ident, 108 with_bounds: Punctuated, 109 tr: &ItemTrait, 110) -> TokenStream { 111 let bounds: Vec<_> = with_bounds 112 .into_iter() 113 .map(|b| TypeParamBound::Trait(b.clone())) 114 .collect(); 115 let variant = ItemTrait { 116 ident: variant.clone(), 117 supertraits: tr.supertraits.iter().chain(&bounds).cloned().collect(), 118 items: tr 119 .items 120 .iter() 121 .map(|item| transform_item(item, &bounds)) 122 .collect(), 123 ..tr.clone() 124 }; 125 quote! { #variant } 126} 127 128// Transforms one item declaration within the definition if it has `async fn` and/or `-> impl Trait` return types by adding new bounds. 129fn transform_item(item: &TraitItem, bounds: &Vec) -> TraitItem { 130 let TraitItem::Fn(fn_item @ TraitItemFn { sig, .. }) = item else { 131 return item.clone(); 132 }; 133 let (arrow, output) = if sig.asyncness.is_some() { 134 let orig = match &sig.output { 135 ReturnType::Default => quote! { () }, 136 ReturnType::Type(_, ty) => quote! { #ty }, 137 }; 138 let future = syn::parse2(quote! { ::core::future::Future }).unwrap(); 139 let ty = Type::ImplTrait(TypeImplTrait { 140 impl_token: syn::parse2(quote! { impl }).unwrap(), 141 bounds: iter::once(TypeParamBound::Trait(future)) 142 .chain(bounds.iter().cloned()) 143 .collect(), 144 }); 145 (syn::parse2(quote! { -> }).unwrap(), ty) 146 } else { 147 match &sig.output { ``` -------------------------------- ### Expanded trait definition Source: https://docs.rs/trait-variant/latest/src/trait_variant/lib.rs.html This shows the resulting trait definition after the #[make(Send)] macro is applied. ```rust # use core::future::Future; trait IntFactory: Send { fn make(&self) -> impl Future + Send; fn stream(&self) -> impl Iterator + Send; fn call(&self) -> u32; } ``` -------------------------------- ### Handle Trait Items in Blanket Implementation Source: https://docs.rs/trait-variant/latest/src/trait_variant/variant.rs.html Processes individual trait items (constants, functions, types) to generate their corresponding implementations within a blanket impl block. It maps trait items to their specific implementations for the blanket. ```rust fn blanket_impl_item( item: &TraitItem, variant: &Ident, trait_ty_generics: &TypeGenerics<'_>, ) -> TokenStream { match item { TraitItem::Const(TraitItemConst { .. }) => { quote! { const #ident #generics: #ty = ::#ident; } } TraitItem::Fn(TraitItemFn { sig, .. }) => { let ident = &sig.ident; let args = sig.inputs.iter().map(|arg| match arg { FnArg::Receiver(_) => quote! { self }, FnArg::Typed(PatType { pat, .. }) => match &**pat { Pat::Ident(arg) => quote! { #arg }, _ => Error::new_spanned(pat, "patterns are not supported in arguments") .to_compile_error(), }, }); let maybe_await = if sig.asyncness.is_some() { quote! { .await } } else { quote! {} }; quote! { #sig { ::#ident(#(#args),*)#maybe_await } } } TraitItem::Type(TraitItemType { .. }) => { let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); quote! { type #ident #impl_generics = ::#ident #ty_generics #where_clause; } } _ => Error::new_spanned(item, "unsupported item type").into_compile_error(), } } ``` -------------------------------- ### Attribute Macro: #[trait_variant::make] Source: https://docs.rs/trait-variant/latest/index.html The make attribute macro generates a specialized version of a base trait, allowing for the addition of bounds (e.g., Send) to async functions and impl Trait return types. ```APIDOC ## #[trait_variant::make(TraitName: Bounds)] ### Description Creates a specialized version of a base trait that adds specified bounds to `async fn` and/or `-> impl Trait` return types. ### Usage ```rust #[trait_variant::make(IntFactory: Send)] trait LocalIntFactory { async fn make(&self) -> i32; fn stream(&self) -> impl Iterator; fn call(&self) -> u32; } ``` ### Generated Output This generates a new trait `IntFactory` where the async functions and return types are constrained by the specified bounds (e.g., `+ Send`). ``` -------------------------------- ### Generate a specialized trait with trait_variant::make Source: https://docs.rs/trait-variant/latest/trait_variant Use the make attribute macro to create a Send-bound version of a base trait. ```rust #[trait_variant::make(IntFactory: Send)] trait LocalIntFactory { async fn make(&self) -> i32; fn stream(&self) -> impl Iterator; fn call(&self) -> u32; } ``` ```rust use core::future::Future; trait IntFactory: Send { fn make(&self) -> impl Future + Send; fn stream(&self) -> impl Iterator + Send; fn call(&self) -> u32; } ``` -------------------------------- ### Construct Blanket Implementation for Trait Variant Source: https://docs.rs/trait-variant/latest/src/trait_variant/variant.rs.html Generates a blanket implementation for a given trait variant. This is useful for providing default implementations across different types that satisfy the trait. ```rust fn mk_blanket_impl(variant: &Ident, tr: &ItemTrait) -> TokenStream { let orig = &tr.ident; let (_impl, orig_ty_generics, _where) = &tr.generics.split_for_impl(); let items = tr .items .iter() .map(|item| blanket_impl_item(item, variant, orig_ty_generics)); let blanket_bound: TypeParam = parse_quote!(TraitVariantBlanketType: #variant #orig_ty_generics); let blanket = &blanket_bound.ident.clone(); let mut blanket_generics = tr.generics.clone(); blanket_generics .params .push(GenericParam::Type(blanket_bound)); let (blanket_impl_generics, _ty, blanket_where_clause) = &blanket_generics.split_for_impl(); quote! { impl #blanket_impl_generics #orig #orig_ty_generics for #blanket #blanket_where_clause { #(#items)* } } } ``` -------------------------------- ### Handle Return Type in Trait Function Signature Source: https://docs.rs/trait-variant/latest/src/trait_variant/variant.rs.html Processes the return type of a trait function signature, specifically handling `ImplTrait` by merging bounds. This is part of constructing a modified function signature. ```rust ReturnType::Type(arrow, ty) => match &**ty { Type::ImplTrait(it) => { let ty = Type::ImplTrait(TypeImplTrait { impl_token: it.impl_token, bounds: it.bounds.iter().chain(bounds).cloned().collect(), }); (*arrow, ty) } _ => return item.clone(), }, ReturnType::Default => return item.clone(), } ``` -------------------------------- ### proc_macro_attribute #[make] Source: https://docs.rs/trait-variant/latest/src/trait_variant/lib.rs.html The #[make] attribute macro is used to generate a specialized version of a trait with added bounds on async functions and return types. ```APIDOC ## #[make] ### Description Creates a specialized version of a base trait that adds bounds (e.g., Send) to `async fn` and/or `-> impl Trait` return types. ### Parameters - **attr** (TokenStream) - The trait bounds to apply (e.g., Send or TraitName: Send). - **item** (TokenStream) - The original trait definition to be processed. ### Usage Example ```rust #[trait_variant::make(Send)] trait IntFactory { async fn make(&self) -> i32; fn stream(&self) -> impl Iterator; fn call(&self) -> u32; } ``` ``` -------------------------------- ### Create a separate trait variant Source: https://docs.rs/trait-variant/latest/trait_variant/attr.make.html Creates a new trait variant while keeping the original trait definition untouched. ```rust #[trait_variant::make(IntFactory: Send)] trait LocalIntFactory { async fn make(&self) -> i32; fn stream(&self) -> impl Iterator; fn call(&self) -> u32; } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.