easy_macros_attributes/
lib.rs

1/// Internal implementation details. Not intended for direct use.
2pub mod internal;
3
4/// Reexport of helper utilities for the procedural macros.
5pub mod helpers {
6    pub use helpers::*;
7}
8
9#[cfg(test)]
10mod examples;
11
12// Compile README.docify.md to README.md
13#[cfg(feature = "generate-readme")]
14docify::compile_markdown!("README.docify.md", "README.md");
15
16// Re-export for use by proc-macro crate (but hidden in internal module)
17#[doc(hidden)]
18pub use internal::AttrWithUnknown;
19
20/// Checks if an item has all specified attributes.
21///
22/// Returns `true` if the passed in item has all specified attributes (one or more).
23///
24/// # Syntax
25/// ```rust,ignore
26/// has_attributes!(item, #[attribute1] #[attribute2] ... #[attributeN])
27/// ```
28///
29/// # Arguments
30/// * `item` - Any syntax node that has an `.attrs` field (e.g., struct, enum, function, field)
31/// * `attributes` - One or more attributes to check for (all must be present)
32///
33/// # Return Value
34/// Returns a boolean expression that evaluates to `true` if ALL specified attributes
35/// are found on the item, `false` otherwise.
36///
37/// # Matching Behavior
38/// **IMPORTANT**: This macro performs **exact matching** on attributes. The entire attribute
39/// must match exactly, including all tokens and their structure.
40///
41/// - `#[derive(Debug)]` matches ONLY `#[derive(Debug)]`, NOT `#[derive(Debug, Clone)]`
42/// - `#[serde(rename = "x")]` matches ONLY that exact attribute with that exact value
43/// - Token structure must match exactly (whitespace is normalized and doesn't need to match)
44///
45/// # Examples
46///
47/// ## Basic Usage
48#[doc = docify::embed!("src/examples.rs", has_attributes_basic_usage)]
49///
50/// ## Field Attributes
51#[doc = docify::embed!("src/examples.rs", has_attributes_field_attributes)]
52///
53/// ## Exact Matching Gotchas
54#[doc = docify::embed!("src/examples.rs", has_attributes_exact_matching)]
55///
56/// # Error Handling
57/// This macro performs attribute parsing at compile time and will produce compile errors if:
58/// - The `item` parameter doesn't have an `.attrs` field (e.g., not a valid syntax node)
59/// - The attribute syntax is malformed (invalid Rust attribute syntax)
60/// - No attributes are provided to check for
61///
62///
63/// # Use Cases
64/// - Validation in derive macros (checking for required companion attributes)
65/// - Configuration checks in procedural macros
66/// - Conditional code generation based on attribute presence
67/// - Guard clauses to ensure required attributes exist
68pub use attributes_macros::has_attributes;
69
70/// Extracts dynamic values from attributes using `__unknown__` placeholders.
71///
72/// This macro allows pattern matching against attributes where some parts are unknown
73/// and need to be extracted. Use `__unknown__` as a placeholder for the parts you want
74/// to capture.
75///
76/// # Syntax
77/// ```rust,ignore
78/// get_attributes!(item, #[pattern_with___unknown__])
79/// ```
80///
81/// # Arguments
82/// * `item` - Any syntax node that has an `.attrs` field
83/// * `pattern` - Attribute pattern with exactly one `__unknown__` placeholder
84///
85/// # Return Value
86/// Returns `Vec<proc_macro2::TokenStream>` containing all the unknown replacements
87/// found on the item. Each `TokenStream` represents the content that replaced `__unknown__`
88/// in a matching attribute.
89///
90/// - **Empty vector `vec![]`**: No matching attributes found, or conditional attributes missing
91/// - **Non-empty vector**: Each element is an extracted unknown replacement
92/// - **Ordering**: Matches appear in the same order as attributes on the item
93///
94/// # `__unknown__` Placement Rules
95/// 1. **Exactly one per pattern**: Only one `__unknown__` is allowed per attribute pattern
96/// 2. **Flexible positioning**: Can appear anywhere in the attribute
97/// 3. **Partial matching**: Can match parts of identifiers or literals
98/// 4. **Requires exact match**: All non-unknown parts must match exactly
99///
100/// # Examples
101///
102/// ## Basic Value Extraction
103#[doc = docify::embed!("src/examples.rs", get_attributes_basic_value_extraction)]
104///
105/// ## Partial Identifier Matching
106#[doc = docify::embed!("src/examples.rs", get_attributes_partial_identifier_matching)]
107///
108/// ## Function Parameter Extraction
109#[doc = docify::embed!("src/examples.rs", get_attributes_function_parameter_extraction)]
110///
111/// ## Complex Nested Matching
112#[doc = docify::embed!("src/examples.rs", get_attributes_nested_example)]
113///
114/// ## Conditional Extraction with Multiple Attributes
115#[doc = docify::embed!("src/examples.rs", get_attributes_conditional_extraction)]
116///
117/// # Error Handling
118/// - **Compile Error**: if no `__unknown__` placeholder is found in any attribute
119/// - **Compile Error**: if multiple `__unknown__` placeholders are used in a single pattern  
120/// - **Returns `vec![]`**: if no matching attributes are found on the item
121/// - **Returns `vec![]`**: if conditional attributes (non-unknown) are missing
122/// - Provides detailed error context via `anyhow::Error` for debugging
123///
124/// # Error Examples
125///
126/// ## Multiple Unknowns (Compile Error)
127/// ```rust,compile_fail
128/// # use attributes::get_attributes;
129/// # use syn::parse_quote;
130/// # let input: syn::ItemStruct = parse_quote! { struct Foo; };
131/// // ❌ This will fail to compile!
132/// let invalid = get_attributes!(
133///     input,
134///     #[route(__unknown__, __unknown__)]
135/// );
136/// // Error: Multiple unknowns found in attributes!
137/// ```
138///
139/// ## No Unknown (Compile Error)  
140/// ```rust,compile_fail
141/// # use attributes::get_attributes;
142/// # use syn::parse_quote;
143/// # let input: syn::ItemStruct = parse_quote! { struct Foo; };
144/// // ❌ This will fail to compile!
145/// let invalid = get_attributes!(
146///     input,
147///     #[derive(Debug)]
148/// );
149/// // Error: No unknown found in (to search for) attributes!
150/// ```
151///
152/// ## No Matches (Returns Empty Vec)
153#[doc = docify::embed!("src/examples.rs", error_handling_no_matches_example)]
154///
155/// ## Conditional Missing (Returns Empty Vec)  
156#[doc = docify::embed!("src/examples.rs", error_handling_conditional_missing_example)]
157///
158/// # Common Mistakes
159///
160///
161/// ## Exact Matching Required
162#[doc = docify::embed!("src/examples.rs", get_attributes_exact_matching_required)]
163///
164/// # Use Cases
165/// - Configuration extraction from attributes
166/// - Building route handlers from attribute metadata
167/// - Extracting validation rules
168/// - Code generation based on attribute parameters
169/// - Creating domain-specific languages in attributes
170pub use attributes_macros::get_attributes;
171
172/// Filters struct/enum fields by their attributes.
173///
174/// This macro examines the fields of a struct and returns an iterator over
175/// fields that contain ALL of the specified attributes. Supports borrowing patterns
176/// to control ownership of the returned fields.
177///
178/// **Note**: This macro uses [`has_attributes!`] internally, which performs **exact**
179/// attribute matching. See [`has_attributes!`] documentation for matching behavior details.
180///
181/// # Syntax
182/// ```rust,ignore
183/// fields_with_attributes!(item, #[attr1] #[attr2] ... #[attrN])
184/// fields_with_attributes!(&item, #[attr1] #[attr2])      // immutable borrow
185/// fields_with_attributes!(&mut item, #[attr1] #[attr2])  // mutable borrow
186/// ```
187///
188/// # Arguments
189/// * `item` - A struct (optionally borrowed) that has a `.fields` field
190/// * `attributes` - One or more attributes that must ALL be present on a field (exact match)
191///
192/// # Return Value
193/// Returns an iterator over `(usize, Field)` tuples where:
194/// - `usize` is the 0-based index of the field (0 for first field, 1 for second, etc.)
195/// - `Field` is `syn::Field`, `&syn::Field`, or `&mut syn::Field` depending on borrowing
196///
197/// # Borrowing Behavior
198/// - **No prefix**: `fields.into_iter()` - consumes the fields, returns owned `syn::Field`
199/// - **`&` prefix**: `fields.iter()` - immutable references, returns `&syn::Field`
200/// - **`&mut` prefix**: `fields.iter_mut()` - mutable references, returns `&mut syn::Field`
201///
202/// # Examples
203///
204/// ## Basic Field Filtering
205#[doc = docify::embed!("src/examples.rs", fields_with_attributes_basic_filtering)]
206///
207/// ## Multiple Attribute Requirements (Exact Match)
208#[doc = docify::embed!("src/examples.rs", fields_with_attributes_multiple_requirements)]
209///
210/// **Note**: Exact matching means `#[serde(rename = "user_name", skip_serializing_if = "Option::is_none")]`
211/// won't match `#[serde(rename = "user_name")]` because it has additional content.
212///
213/// ## Borrowing to Preserve Original
214#[doc = docify::embed!("src/examples.rs", fields_with_attributes_borrowing)]
215///
216/// # Error Handling
217/// This macro will produce compile errors if:
218/// - The `item` parameter doesn't have a `.fields` field
219/// - The attribute syntax is malformed
220/// - No attributes are provided to match against
221///
222/// The macro returns an iterator, so no fields matching the criteria simply results in an empty iterator (not an error).
223///
224pub use attributes_macros::fields_with_attributes;
225
226/// Extracts dynamic values from field attributes using `__unknown__` placeholders.
227///
228/// This macro combines field filtering with attribute pattern extraction. It examines
229/// struct/enum fields and returns those that match the attribute pattern, along with
230/// the extracted unknown parts from their attributes.
231///
232/// **Note**: This uses [`get_attributes!`] internally for pattern matching. A field can
233/// have multiple matching attributes, resulting in multiple extracted values for that field.
234///
235/// # Syntax
236/// ```rust,ignore
237/// fields_get_attributes!(item, #[pattern_with___unknown__])
238/// fields_get_attributes!(&item, #[pattern_with___unknown__])      // immutable borrow
239/// fields_get_attributes!(&mut item, #[pattern_with___unknown__])  // mutable borrow
240/// ```
241///
242/// # Arguments
243/// * `item` - A struct (optionally borrowed) that has a `.fields` field
244/// * `pattern` - Attribute pattern with exactly one `__unknown__` placeholder
245///
246/// # Return Value
247/// Returns `Vec<(usize, Field, Vec<proc_macro2::TokenStream>)>` where:
248/// - `usize` is the 0-based index of the field
249/// - `Field` is `syn::Field`, `&syn::Field`, or `&mut syn::Field` depending on borrowing
250/// - `Vec<proc_macro2::TokenStream>` contains all unknown replacements found on that field
251///
252/// **Important**: A single field can have multiple matching attributes, so the `Vec<TokenStream>`
253/// can contain multiple elements. If a field has no matching attributes, it won't appear in the results.
254///
255/// # Error Handling
256/// - If any field causes an error during extraction, the macro will return that error
257/// - See [`get_attributes!`] for specific error conditions
258/// - Fields that don't match the pattern are silently skipped (not an error)
259///
260/// # Examples
261///
262/// ## Route Configuration Extraction
263#[doc = docify::embed!("src/examples.rs", fields_get_attributes_route_extraction)]
264///
265/// ## Database Column Configuration
266#[doc = docify::embed!("src/examples.rs", fields_get_attributes_database_columns)]
267///
268/// ## Validation Rule Extraction
269#[doc = docify::embed!("src/examples.rs", fields_get_attributes_validation_rules)]
270///
271/// ## Multiple Matching Attributes Per Field (Important!)
272#[doc = docify::embed!("src/examples.rs", fields_get_attributes_multiple_matches_per_field)]
273///
274/// ## Borrowing for Memory Efficiency
275#[doc = docify::embed!("src/examples.rs", fields_get_attributes_borrowing)]
276///
277/// ## Complex Pattern Matching
278#[doc = docify::embed!("src/examples.rs", fields_get_attributes_complex_pattern)]
279///
280/// # Error Handling
281/// - **Compile Error**: if no `__unknown__` placeholder is found in the pattern
282/// - **Compile Error**: if multiple `__unknown__` placeholders are used  
283/// - **Compile Error**: if the `item` parameter doesn't have a `.fields` field
284/// - **Returns `vec![]`**: if no fields match the attribute pattern
285/// - **Runtime Error**: if attribute parsing fails for any field (propagated via `anyhow::Error`)
286///
287/// If any field causes a parsing error, the entire macro invocation fails with a detailed error message
288/// including the problematic field's information.
289///
290/// # Use Cases
291/// - **Derive macro implementations**: Generate code based on field attributes (e.g., route handlers, database columns)
292/// - **Configuration extraction**: Pull metadata from field attributes for code generation
293/// - **Validation rule collection**: Gather all validation attributes across struct fields
294/// - **API endpoint generation**: Build routing tables from field-level route attributes
295/// - **ORM mapping**: Extract database column configurations from field attributes
296/// - **Serialization customization**: Process field-level serialization directives
297///
298pub use attributes_macros::fields_get_attributes;