Easy Macros
Use the parent crate instead.
What is this?
This crate provides procedural macros for working with Rust attributes. It enables pattern matching, extraction, and filtering based on attributes in your code, with support for unknown placeholders and flexible matching patterns.
Core Features
Attribute Checking
has_attributes!- Check if an item has all specified attributes
Attribute Pattern Matching with Unknowns
get_attributes!- Extract dynamic values from attributes using__unknown__placeholders
Field-Level Attribute Operations
fields_with_attributes!- Filter struct/enum fields by their attributesfields_get_attributes!- Extract dynamic values from field attributes
Advanced Pattern Matching
AttrWithUnknown- Advanced attribute parsing with unknown placeholder support
Examples
Basic Attribute Checking with has_attributes!
use parse_quote;
// Check for a single attribute
let input: ItemStruct = parse_quote! ;
let has_debug = has_attributes!;
assert!;
// Check for multiple attributes (all must be present)
let has_both = has_attributes!;
assert!;
// This returns false since #[derive(Clone)] is not present
let has_clone = has_attributes!;
assert!;
Pattern Matching with get_attributes! and __unknown__
The __unknown__ placeholder allows you to extract dynamic parts from attributes:
Basic Value Extraction
use parse_quote;
let input: ItemStruct = parse_quote! ;
// Extract rename values
let renames: = get_attributes!;
assert_eq!;
assert_eq!;
assert_eq!;
Ok
Partial Identifier Matching
use parse_quote;
let input: ItemStruct = parse_quote! ;
// Extract the suffix after "test_case_"
let test_cases: = get_attributes!;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
Ok
Field-Level Operations with fields_with_attributes!
Filter struct fields based on their attributes:
Basic Field Filtering
use fields_with_attributes;
use parse_quote;
let input: ItemStruct = parse_quote! ;
// Get fields with validation attributes
let validated_fields: = fields_with_attributes!
.collect;
assert_eq!; // name and email fields
assert_eq!; // name is at index 1
assert_eq!;
Multiple Attribute Requirements
use fields_with_attributes;
use parse_quote;
let input: ItemStruct = parse_quote! ;
// Get fields that have BOTH validate AND the exact serde attribute
let validated_serde_fields: = fields_with_attributes!
.collect;
assert_eq!;
Note: Exact matching means #[serde(rename = "user_name", skip_serializing_if = "Option::is_none")]
won't match #[serde(rename = "user_name")] because it has additional content.
Advanced Pattern Extraction with fields_get_attributes!
Extract dynamic values from field attributes:
Route Configuration Extraction
use ;
use parse_quote;
let input: ItemStruct = parse_quote! ;
// Extract HTTP methods for all route fields
let methods: =
fields_get_attributes!;
assert_eq!; // get_users and create_user
assert_eq!; // get_users method
assert_eq!; // create_user method
Ok
Database Column Configuration
use fields_get_attributes;
use parse_quote;
let input: ItemStruct = parse_quote! ;
// Extract column types
let column_types: =
fields_get_attributes!;
assert_eq!; // only email field
assert_eq!;
Ok
Complex Pattern Matching Scenarios
Nested Attribute Matching
use parse_quote;
// Docify has trouble parsing parse_quote! with attributes inside,
// so we use a string literal workaround
let input: ItemStruct = parse_str?;
// Extract database URL
let db_urls: = get_attributes!;
assert_eq!
Multiple Matching Attributes Per Field
use fields_get_attributes;
use parse_quote;
// **KEY CONCEPT**: A single field can have MULTIPLE matching attributes!
// Each matching attribute on the same field adds to the Vec<TokenStream>
let input: ItemStruct = parse_quote! ;
let versions: =
fields_get_attributes!;
assert_eq!; // ONE field in results
assert_eq!; // THREE extracted values from that field
assert_eq!;
assert_eq!;
assert_eq!;
Ok
Integration in Procedural Macros
use TokenStream;
use quote;
use ;
use ;
Understanding __unknown__ Placeholders
The __unknown__ placeholder is a powerful feature that allows pattern matching in attributes:
Placement Rules
- Single unknown per attribute pattern: Only one
__unknown__is allowed per attribute pattern - Flexible positioning: Can appear in identifiers, literals, or as standalone tokens
- Partial matching: Can match parts of identifiers (e.g.,
prefix___unknown___suffix)
Matching Behavior
- Exact match required: All non-unknown parts must match exactly
- Multiple captures: Same pattern can match multiple attributes, collecting all unknowns
- Type preservation: Unknown content is captured as
proc_macro2::TokenStream
Common Patterns
// Method extraction
// Captures HTTP method
// Path parameter extraction
// Captures full path
// Partial identifier matching
// Captures suffix of test attributes
// Value extraction from key-value pairs
// Captures configuration values
// Nested structure matching
// Captures inner content
Error Handling
All macros return empty results or compile errors with detailed messages:
No Matches (Returns Empty)
use parse_quote;
let input: ItemStruct = parse_quote! ;
// No #[route(...)] attributes exist, so this returns empty
let no_routes: = get_attributes!;
assert_eq!;
Ok
Conditional Attributes Missing
use parse_quote;
// Missing the required #[derive(Debug)] attribute
let input_no_debug: ItemStruct = parse_quote! ;
// Without derive(Debug), this returns empty vec![]
let no_versions: = get_attributes!;
assert_eq!; // Empty because derive(Debug) is missing
Ok
For more error handling examples, see the documentation.
Performance Considerations
- Compile-time execution: All processing happens at compile time
- Efficient pattern matching: Uses optimized string matching for unknown detection
- Minimal runtime overhead: Generated code has zero runtime cost
- Caching: Repeated patterns are efficiently processed
Integration with Easy Macros Ecosystem
This crate is part of the larger Easy Macros ecosystem and integrates seamlessly with other components:
- Easy Macros Helpers: Provides underlying utilities
- Easy Macros: Main entry point with all features
- Context generation: Automatic error context using
context! - Token stream utilities: Built on
TokensBuilder
Note: All examples in this README are tested as part of the test suite. See src/examples.rs for the full, runnable code.