Expand description
Helper methods and macros for analyzing and manipulating generic bounds in Rust proc-macro crates.
This crate provides utilities built on top of the syn crate to track which generic parameters
are referenced in a syntax tree, extract bounded generics, and manipulate lifetime parameters.
§Overview
The primary type is BoundGenerics, which implements the syn::visit::Visit trait to track
which generic parameters (types, lifetimes, and consts) are referenced in an AST subtree. This is
particularly useful when writing derive macros or other procedural macros that need to:
- Determine which generic parameters are actually used in a struct or enum
- Extract only the relevant where clauses for used parameters
- Create minimal generic bounds for generated implementations
§Examples
use syn::{parse_quote, DeriveInput};
use syn::visit::Visit;
use synbounds::BoundGenerics;
// Parse a struct definition
let input: DeriveInput = parse_quote! {
struct MyStruct<'a, T, U> {
field: &'a T,
}
};
// Track which generics are used in the fields
let mut bounds = BoundGenerics::new(&input.generics);
if let syn::Data::Struct(data) = &input.data {
bounds.visit_fields(&data.fields);
}
// Only T and 'a are used, U is not
let bound_generics = bounds.to_bound_generics();§Analyzing Impl Blocks
use syn::{parse_quote, ItemImpl};
use syn::visit::Visit;
use synbounds::BoundGenerics;
// Parse an impl block
let item: ItemImpl = parse_quote! {
impl<T, U, V> MyStruct<T> {
fn process(&self, value: U) -> String {
unimplemented!()
}
}
};
// Track which generics are used in method signatures
let mut bounds = BoundGenerics::new(&item.generics);
bounds.visit_type(&item.self_ty); // Visit self type
for impl_item in &item.items {
if let syn::ImplItem::Fn(method) = impl_item {
bounds.visit_signature(&method.sig);
}
}
// T and U are used, V is not
let bound_generics = bounds.to_bound_generics();§Substituting Lifetimes
The crate also provides utilities for replacing lifetimes in syntax trees (requires the
substitute feature, enabled by default):
use syn::{parse_quote, Type};
use syn::visit_mut::VisitMut;
use synbounds::substitute_with_static_lifetime;
// Replace all lifetimes with 'static
let mut ty: Type = parse_quote! { &'a Vec<&'b str> };
let mut visitor = substitute_with_static_lifetime();
visitor.visit_type_mut(&mut ty);
// ty is now: &'static Vec<&'static str>You can also substitute with a specific lifetime using substitute_with_lifetime:
use syn::{parse_quote, Type, Lifetime};
use syn::visit_mut::VisitMut;
use synbounds::substitute_with_lifetime;
let target_lifetime: Lifetime = parse_quote! { 'target };
let mut ty: Type = parse_quote! { &'a String };
let mut visitor = substitute_with_lifetime(&target_lifetime);
visitor.visit_type_mut(&mut ty);
// ty is now: &'target StringOr create custom substitution logic with SubstituteLifetimes:
use syn::{parse_quote, Type, Lifetime};
use syn::visit_mut::VisitMut;
use synbounds::SubstituteLifetimes;
let mut ty: Type = parse_quote! { &'a String };
let mut visitor = SubstituteLifetimes(|lifetime: &mut Lifetime| {
if lifetime.ident == "a" {
*lifetime = Lifetime::new("'long", lifetime.span());
}
});
visitor.visit_type_mut(&mut ty);
// ty is now: &'long String§Substituting Self Types
When generating wrapper types or helper functions, you often need to replace Self with
the concrete type. The SubstituteSelfType visitor handles this:
use syn::{parse_quote, Type};
use syn::visit_mut::VisitMut;
use synbounds::SubstituteSelfType;
let concrete_type: Type = parse_quote! { MyStruct<T, U> };
let mut return_type: Type = parse_quote! { Result<Self, Error> };
let mut visitor = SubstituteSelfType::new(&concrete_type);
visitor.visit_type_mut(&mut return_type);
// return_type is now: Result<MyStruct<T, U>, Error>This is especially useful when defining private wrapper objects for functions that use Self:
use syn::{parse_quote, Signature, Type};
use syn::visit_mut::VisitMut;
use synbounds::SubstituteSelfType;
// Original method signature with Self
let mut sig: Signature = parse_quote! {
fn process(input: &Self) -> Option<Self>
};
let concrete: Type = parse_quote! { MyStruct<'a, T> };
let mut visitor = SubstituteSelfType::new(&concrete);
visitor.visit_signature_mut(&mut sig);
// Signature now uses: MyStruct<'a, T> instead of Self§Features
proc-macro(default): Enable proc-macro supportfull(optional): Enable full syn feature for additional syntax supportsubstitute(default): Enable lifetime substitution utilities
Structs§
- Bound
Generics - A
syn::visit::Visitthat tracks which generic parameters are bound. - Contains
Bound Generics - A
syn::visit::Visitthat tests whether any of the given generic parameters are contained and whether they are bound or unbound. - Substitute
Lifetimes substitute - A
syn::visit_mut::VisitMutthat substitutes lifetimes according to the provided function. - Substitute
Self Type substitute - A
syn::visit_mut::VisitMutthat substitutes theSelftype with a concrete type.
Enums§
- Generic
Param Ref - A reference to a generic parameter: type, lifetime, or const.
Functions§
- substitute_
self_ type substitute - Creates a
SubstituteSelfTypevisitor that substitutesSelftypes with the provided concrete type. - substitute_
with_ lifetime substitute - Creates a
SubstituteLifetimesvisitor that substitutes all non-'staticlifetimes with the provided lifetime. - substitute_
with_ static_ lifetime substitute - Creates a
SubstituteLifetimesvisitor that substitutes all non-'staticlifetimes with'static.