synbounds
synbounds is a Rust crate that provides utilities for writing proc-macro crates that need to manipulate or analyze Rust type bounds.
It leverages the syn crate to parse and work with Rust syntax trees, making it easier to handle complex type bounds in procedural macros.
Features
- Track Generic Usage: Automatically determine which generic parameters (types, lifetimes, consts) are actually used in your code
- Extract Minimal Bounds: Generate minimal
whereclauses containing only the predicates for used generics - Lifetime Substitution: Utilities for replacing lifetimes in syntax trees
- Self Type Substitution: Replace
Selfwith concrete types in method signatures and return types
Usage
Add this to your Cargo.toml:
[]
= "0.1"
Example: Tracking Used Generics
use ;
use Visit;
use BoundGenerics;
// Parse a struct definition
let input: DeriveInput = parse_quote! ;
// Track which generics are used in the fields
let mut bounds = new;
if let Struct = &input.data
// Only T and 'a are used, U is not
let bound_generics = bounds.to_bound_generics;
// bound_generics is now: <'a, T>
Example: Filtering Where Clauses
use ;
use Visit;
use BoundGenerics;
let input: DeriveInput = parse_quote! ;
let mut bounds = new;
if let Struct = &input.data
// Only get where predicates for used generics (T)
let where_predicates: = bounds.bound_where_predicates.collect;
// where_predicates contains only: T: Clone
Example: Analyzing Impl Blocks
use ;
use Visit;
use BoundGenerics;
let item: ItemImpl = parse_quote! ;
// Track which generics are used
let mut bounds = new;
bounds.visit_type;
for impl_item in &item.items
// T and U are used, V is not
let bound_generics = bounds.to_bound_generics;
Example: Lifetime Substitution
use ;
use VisitMut;
use substitute_with_static_lifetime;
let mut ty: Type = parse_quote! ;
let mut visitor = ;
visitor.visit_type_mut;
// ty is now: &'static String
Example: Substituting Self Types
use ;
use VisitMut;
use SubstituteSelfType;
let concrete_type: Type = parse_quote! ;
let mut return_type: Type = parse_quote! ;
let mut visitor = new;
visitor.visit_type_mut;
// return_type is now: Result<MyStruct<T, U>, Error>
This is especially useful when defining private wrapper objects for functions that use Self.
Features
proc-macro(default): Enable proc-macro supportfull: Enable fullsynfeature for additional syntax supportsubstitute(default): Enable lifetime substitution utilities
Use Cases
This crate is particularly useful when:
- Writing derive macros that need to determine which generic parameters are actually used
- Generating trait implementations with minimal bounds
- Analyzing AST nodes to extract relevant generic constraints
- Creating procedural macros that manipulate lifetime parameters
Background
When writing a proc-macro for a specific library, I came across the problem, that I needed to know
which generic bounds where actually used on a specific part of the AST (Functions in impl blocks
to be precise).
While syn provides the necessary structures to parse and represent these bounds, it does not
provide utilities to easily extract or manipulate them. So I first wrote some helper functions for
my specific use case.
Later I came across the synstructure crate, which provided some similar functionality, but was
more focused on deriving implementations for enums and structs. But this inspired me to generalize
and refactor my helper functions into a standalone crate that could be reused in other
proc-macro projects.
License
This project is licensed under either of
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
- Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.