Function macro_tools::protected::generic_params::decompose

source ·
pub fn decompose(
    generics: &Generics,
) -> (Punctuated<GenericParam, Comma>, Punctuated<GenericParam, Comma>, Punctuated<GenericParam, Comma>, Punctuated<WherePredicate, Comma>)
Expand description

Decomposes syn::Generics into components suitable for different usage contexts in Rust implementations, specifically focusing on different requirements for impl blocks and type definitions.

This function prepares three versions of the generics:

  • One preserving the full structure for impl declarations.
  • One simplified for type definitions, removing bounds and defaults from type and const parameters, retaining only identifiers.
  • One for the where clauses, if present, ensuring they are correctly punctuated.

This helps in situations where you need different representations of generics for implementing traits, defining types, or specifying trait bounds and conditions.

This function is similar to syn::Generics::split_for_impl, which also splits generics into components suitable for impl blocks and type definitions. However, split_for_impl wraps the tokens in <>, which can reduce the flexibility of the results. The decompose function provides more control over the output by not wrapping the tokens, allowing for more precise usage in macros and other contexts. Additionally, decompose returns an extra component with the generics including defaults, which is often in demand for certain macro or code generation tasks.

§Examples

let code : syn::Generics = syn::parse_quote!{ <'a, T, const N : usize, U : Trait1> };
let ( generics_with_defaults, generics_for_impl, generics_for_ty, generics_where ) = macro_tools::generic_params::decompose( &code );

// Use in a macro for generating code
macro_tools::qt!
{
  impl < #generics_for_impl > MyTrait for Struct1 < #generics_for_ty >
  where
    #generics_where
  {
    // implementation details...
  }
};

§Arguments

  • generics - A reference to the syn::Generics to be decomposed.

§Returns

Returns a tuple containing:

  • syn::punctuated::Punctuated<syn::GenericParam, syn::token::Comma>: Original generics with defaults, used where full specification is needed.
  • syn::punctuated::Punctuated<syn::GenericParam, syn::token::Comma>: Generics for impl blocks, retaining bounds but no defaults.
  • syn::punctuated::Punctuated<syn::GenericParam, syn::token::Comma>: Simplified generics for type definitions, only identifiers.
  • syn::punctuated::Punctuated<syn::WherePredicate, syn::token::Comma>: Where clauses, properly punctuated for use in where conditions.

§Differences from syn::Generics::split_for_impl

While both decompose and split_for_impl functions split generics into components for impl blocks, type definitions, and where clauses, there are key differences:

  • split_for_impl wraps the generics in <>, which can be limiting when you need to use the generics in a different context or format.
  • decompose provides raw punctuated generic parameters, offering greater flexibility and control over the output format.
  • decompose returns an extra component with the generics including defaults, which is often needed for certain macro or code generation tasks.

§Example of function signature using decompose

use macro_tools::{ syn, proc_macro2, qt };

fn generate_unit
(
  item_name : &syn::Ident,
  generics_with_defaults : syn::punctuated::Punctuated< syn::GenericParam, syn::token::Comma >,
  generics_impl : syn::punctuated::Punctuated< syn::GenericParam, syn::token::Comma >,
  generics_ty : syn::punctuated::Punctuated< syn::GenericParam, syn::token::Comma >,
  generics_where: syn::punctuated::Punctuated< syn::WherePredicate, syn::token::Comma >,
)
-> proc_macro2::TokenStream
{
  qt!
  {
    #[ automatically_derived ]
    impl< #generics_impl > From< i32 > for #item_name< #generics_ty >
    where
      #generics_where
    {
      #[ inline ]
      fn from( src : i32 ) -> Self
      {
        Wrap( src )
      }
    }
  }
}