Expand description

Traits and types used for tracking the usage of generic parameters through a proc-macro input.

When generating trait impls, libraries often want to automatically figure out which type parameters are used in which fields, and then emit bounds that will produce the most permissive compilable code.

Usage

Example 1: Filtering

This example accepts a proc-macro input, then finds all lifetimes and type parameters used by private fields.

fn process(input: &DeriveInput) -> Generics {
    let type_params = input.generics.declared_type_params();
    let lifetimes = input.generics.declared_lifetimes();

    let mut ret_generics = input.generics.clone();

    if let Data::Struct(ref body) = input.data {
        let internal_fields = body
            .fields
            .iter()
            .filter(|field| field.vis == Visibility::Inherited)
            .collect::<Vec<_>>();

        let int_type_params = internal_fields
            .collect_type_params(&Purpose::BoundImpl.into(), &type_params);

        // We could reuse the vec from above, but here we'll instead
        // directly consume the chained iterator.
        let int_lifetimes = body
            .fields
            .iter()
            .filter(|field| field.vis == Visibility::Inherited)
            .collect_lifetimes(&Purpose::BoundImpl.into(), &lifetimes);


        ret_generics.params = ret_generics
            .params
            .into_iter()
            .filter(|gp| {
                match *gp {
                    GenericParam::Type(ref ty) => int_type_params.contains(&ty.ident),
                    GenericParam::Lifetime(ref lt) => int_lifetimes.contains(&lt.lifetime),
                    _ => true,
                }
            })
            .collect();
    }

    ret_generics
}

Example 2: Integrating with FromDeriveInput

It is possible to use darling’s magic fields feature in tandem with the usage feature set. While there is no custom derive for UsesTypeParams or UsesLifetimes, there are macros to generate impls.

#![allow(dead_code)]

#[derive(FromField)]
#[darling(attributes(speak))]
struct SpeakerField {
    ident: Option<syn::Ident>,
    ty: syn::Type,
    #[darling(default)]
    volume: Option<u32>,
}

uses_type_params!(SpeakerField, ty);
uses_lifetimes!(SpeakerField, ty);

#[derive(FromDeriveInput)]
struct SpeakerOptions {
    generics: syn::Generics,
    data: darling::ast::Data<darling::util::Ignored, SpeakerField>,
}

At this point, you are able to call uses_type_params on SpeakerOptions.data, or any filtered view of it. darling internally uses this in conjunction with the skip meta-item to determine which type parameters don’t require the FromMeta bound in generated impls.

Note: If you are performing operations referencing generic params in meta-items parsed by darling, you should determine if those impact the emitted code and wire up UsesTypeParams accordingly for your field/variant.

Structs

Control struct for searching type parameters.

Enums

The goal of tracing generic parameter usage.

Traits

Searcher for finding lifetimes in an iterator.

Searcher for finding type params in an iterator.

Extension trait for pulling specific generics data from a generics AST representation.

Searcher for finding lifetimes in a syntax tree. This can be used to determine which lifetimes must be emitted in generated code.

Searcher for finding type params in a syntax tree. This can be used to determine if a given type parameter needs to be bounded in a generated impl.

Type Definitions

A set of references to idents.

A set of idents.

A set of references to lifetimes.

A set of lifetimes.