assert_struct_macros/
lib.rs

1//! Procedural macro implementation for assert-struct.
2//!
3//! This crate provides the procedural macro implementation for the `assert-struct` crate.
4//! Users should use the main `assert-struct` crate which re-exports this macro.
5//!
6//! # Architecture Overview
7//!
8//! The macro transformation happens in three phases:
9//!
10//! 1. **Parse** (`parse.rs`): Tokenize the macro input into a Pattern AST
11//! 2. **Expand** (`expand.rs`): Transform patterns into assertion code
12//! 3. **Execute**: Generated code runs the actual assertions
13//!
14//! # Key Design Decisions
15//!
16//! - **Pattern enum**: Unified abstraction for all pattern types (struct, tuple, slice, etc.)
17//! - **Disambiguation**: `check_for_special_syntax` solves `Some(> 30)` vs `Some(my_var)`
18//! - **Dual-path optimization**: String literal regexes compile at expansion time
19//! - **Native Rust syntax**: Use match expressions for ranges, slices, and enums
20//!
21//! See the main `assert-struct` crate for documentation and examples.
22
23use proc_macro::TokenStream;
24use std::fmt;
25use syn::{Expr, Token, punctuated::Punctuated};
26
27mod expand;
28mod parse;
29
30// Root-level struct that tracks the assertion
31struct AssertStruct {
32    value: Expr,
33    pattern: Pattern,
34}
35
36// Unified pattern type that can represent any pattern
37#[derive(Debug, Clone)]
38pub(crate) enum Pattern {
39    // Simple value: 42, \"hello\", true
40    Simple {
41        node_id: usize,
42        expr: Expr,
43    },
44    // Struct pattern: User { name: \"Alice\", age: 30, .. }
45    // When path is None, it's a wildcard pattern: _ { name: \"Alice\", .. }
46    Struct {
47        node_id: usize,
48        path: Option<syn::Path>, // None for wildcard patterns
49        fields: Punctuated<FieldAssertion, Token![,]>,
50        rest: bool,
51    },
52    // Tuple pattern: (10, 20) or Some(42) or None
53    // Now supports mixed positional and indexed elements
54    Tuple {
55        node_id: usize,
56        path: Option<syn::Path>,
57        elements: Vec<TupleElement>,
58    },
59    // Slice pattern: [1, 2, 3] or [1, .., 5]
60    Slice {
61        node_id: usize,
62        elements: Vec<Pattern>,
63    },
64    // Comparison: > 30, <= 100
65    Comparison {
66        node_id: usize,
67        op: ComparisonOp,
68        expr: Expr,
69    },
70    // Range: 10..20, 0..=100
71    Range {
72        node_id: usize,
73        expr: Expr,
74    },
75    // Regex: =~ "pattern" - string literal optimized at compile time
76    #[cfg(feature = "regex")]
77    Regex {
78        node_id: usize,
79        pattern: String, // String literal regex pattern (performance optimization)
80        span: proc_macro2::Span, // Store span for accurate error reporting
81    },
82    // Like pattern: =~ expr - arbitrary expression using Like trait
83    #[cfg(feature = "regex")]
84    Like {
85        node_id: usize,
86        expr: Expr,
87    },
88    // Rest pattern: .. for partial matching
89    Rest {
90        node_id: usize,
91    },
92    // Wildcard pattern: _ for ignoring a value while asserting it exists
93    Wildcard {
94        node_id: usize,
95    },
96    // Closure pattern: |x| expr for custom validation (escape hatch)
97    Closure {
98        node_id: usize,
99        closure: syn::ExprClosure,
100    },
101}
102
103// Helper function to format syn expressions as strings
104fn expr_to_string(expr: &Expr) -> String {
105    // This is a simplified version - in production we'd want more complete handling
106    match expr {
107        Expr::Lit(lit) => {
108            // Handle literals
109            quote::quote! { #lit }.to_string()
110        }
111        Expr::Path(path) => {
112            // Handle paths
113            quote::quote! { #path }.to_string()
114        }
115        Expr::Range(range) => {
116            // Handle ranges
117            quote::quote! { #range }.to_string()
118        }
119        _ => {
120            // Fallback - use quote for other expressions
121            quote::quote! { #expr }.to_string()
122        }
123    }
124}
125
126fn path_to_string(path: &syn::Path) -> String {
127    quote::quote! { #path }.to_string()
128}
129
130impl fmt::Display for Pattern {
131    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132        match self {
133            Pattern::Simple { expr, .. } => {
134                write!(f, "{}", expr_to_string(expr))
135            }
136            Pattern::Struct {
137                path, fields, rest, ..
138            } => {
139                if let Some(p) = path {
140                    write!(f, "{} {{ ", path_to_string(p))?;
141                } else {
142                    write!(f, "_ {{ ")?;
143                }
144                for (i, field) in fields.iter().enumerate() {
145                    if i > 0 {
146                        write!(f, ", ")?;
147                    }
148                    write!(f, "{}: {}", field.field_name, field.pattern)?;
149                }
150                if *rest {
151                    if !fields.is_empty() {
152                        write!(f, ", ")?;
153                    }
154                    write!(f, "..")?;
155                }
156                write!(f, " }}")
157            }
158            Pattern::Tuple { path, elements, .. } => {
159                if let Some(p) = path {
160                    write!(f, "{}", path_to_string(p))?;
161                }
162                write!(f, "(")?;
163                for (i, elem) in elements.iter().enumerate() {
164                    if i > 0 {
165                        write!(f, ", ")?;
166                    }
167                    write!(f, "{}", elem)?;
168                }
169                write!(f, ")")
170            }
171            Pattern::Slice { elements, .. } => {
172                write!(f, "[")?;
173                for (i, elem) in elements.iter().enumerate() {
174                    if i > 0 {
175                        write!(f, ", ")?;
176                    }
177                    write!(f, "{}", elem)?;
178                }
179                write!(f, "]")
180            }
181            Pattern::Comparison { op, expr, .. } => {
182                write!(f, "{} {}", op, expr_to_string(expr))
183            }
184            Pattern::Range { expr, .. } => {
185                write!(f, "{}", expr_to_string(expr))
186            }
187            #[cfg(feature = "regex")]
188            Pattern::Regex { pattern, .. } => {
189                write!(f, r#"=~ r"{}""#, pattern)
190            }
191            #[cfg(feature = "regex")]
192            Pattern::Like { expr, .. } => {
193                write!(f, "=~ {}", expr_to_string(expr))
194            }
195            Pattern::Rest { .. } => {
196                write!(f, "..")
197            }
198            Pattern::Wildcard { .. } => {
199                write!(f, "_")
200            }
201            Pattern::Closure { closure, .. } => {
202                write!(f, "{}", quote::quote! { #closure })
203            }
204        }
205    }
206}
207
208struct Expected {
209    fields: Punctuated<FieldAssertion, Token![,]>,
210    rest: bool, // true if ".." was present
211}
212
213/// Represents an operation to be performed on a field before pattern matching
214#[derive(Debug, Clone)]
215#[allow(dead_code)]
216enum FieldOperation {
217    /// Dereference operation: *field, **field, etc.
218    /// The count indicates how many dereferences to perform
219    Deref { count: usize },
220
221    /// Method call: field.method(), field.len(), etc.
222    /// Stores the method name and arguments (if any)
223    Method {
224        name: syn::Ident,
225        args: Vec<syn::Expr>,
226    },
227
228    /// Nested field access: field.nested, field.inner.value, etc.
229    /// Stores the chain of field names to access
230    Nested { fields: Vec<syn::Ident> },
231
232    /// Index operation: field\[0\], field\[index\], etc.
233    /// Stores the index expression to use
234    Index { index: syn::Expr },
235
236    /// Combined operation: dereferencing followed by method/nested/index access
237    /// Example: *field.method(), **field.inner, *field\[0\], etc.
238    Combined {
239        deref_count: usize,
240        operation: Box<FieldOperation>,
241    },
242
243    /// Chained operations: nested field followed by index or method
244    /// Example: field.nested\[0\], field.inner.method(), field.sub\[1\].len()
245    Chained { operations: Vec<FieldOperation> },
246}
247
248// Field assertion - a field name paired with its expected pattern
249// Now supports operations like dereferencing, method calls, and nested access
250#[derive(Debug, Clone)]
251struct FieldAssertion {
252    field_name: syn::Ident,
253    operations: Option<FieldOperation>,
254    pattern: Pattern,
255}
256
257/// Represents an element in a tuple pattern, supporting both positional and indexed syntax
258#[derive(Debug, Clone)]
259enum TupleElement {
260    /// Positional element: just a pattern in sequence
261    /// Example: "foo", > 10, Some(42)
262    Positional { pattern: Pattern },
263
264    /// Indexed element: explicit index with optional operations
265    /// Example: 0: "foo", *1: "bar", 2.len(): 5
266    Indexed {
267        index: usize,
268        operations: Option<FieldOperation>,
269        pattern: Pattern,
270    },
271}
272impl fmt::Display for TupleElement {
273    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
274        match self {
275            TupleElement::Positional { pattern } => {
276                write!(f, "{}", pattern)
277            }
278            TupleElement::Indexed {
279                index,
280                operations,
281                pattern,
282            } => {
283                if let Some(ops) = operations {
284                    match ops {
285                        FieldOperation::Deref { count } => {
286                            // Show deref operations before the index: *0:
287                            for _ in 0..*count {
288                                write!(f, "*")?;
289                            }
290                            write!(f, "{}: {}", index, pattern)
291                        }
292                        FieldOperation::Method { name, .. } => {
293                            // Show method calls after the index: 0.len():
294                            write!(f, "{}.{}(): {}", index, name, pattern)
295                        }
296                        FieldOperation::Nested { fields } => {
297                            // Show nested access after the index: 0.field:
298                            write!(f, "{}", index)?;
299                            for field in fields {
300                                write!(f, ".{}", field)?;
301                            }
302                            write!(f, ": {}", pattern)
303                        }
304                        FieldOperation::Index { index: idx } => {
305                            // Show index access after the tuple index: 0[1]:
306                            write!(f, "{}[{}]: {}", index, quote::quote! { #idx }, pattern)
307                        }
308                        FieldOperation::Chained { operations } => {
309                            // Show chained operations after the tuple index: 0.field[1]:
310                            write!(f, "{}", index)?;
311                            for op in operations {
312                                match op {
313                                    FieldOperation::Nested { fields } => {
314                                        for field in fields {
315                                            write!(f, ".{}", field)?;
316                                        }
317                                    }
318                                    FieldOperation::Method { name, .. } => {
319                                        write!(f, ".{}()", name)?;
320                                    }
321                                    FieldOperation::Index { index } => {
322                                        write!(f, "[{}]", quote::quote! { #index })?;
323                                    }
324                                    _ => write!(f, "{}", op)?,
325                                }
326                            }
327                            write!(f, ": {}", pattern)
328                        }
329                        FieldOperation::Combined {
330                            deref_count,
331                            operation,
332                        } => {
333                            // Show combined operations: *0.len():
334                            for _ in 0..*deref_count {
335                                write!(f, "*")?;
336                            }
337                            match operation.as_ref() {
338                                FieldOperation::Method { name, .. } => {
339                                    write!(f, "{}.{}(): {}", index, name, pattern)
340                                }
341                                _ => {
342                                    write!(f, "{}{}: {}", index, operation, pattern)
343                                }
344                            }
345                        }
346                    }
347                } else {
348                    write!(f, "{}: {}", index, pattern)
349                }
350            }
351        }
352    }
353}
354
355impl fmt::Display for FieldOperation {
356    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
357        match self {
358            FieldOperation::Deref { count } => {
359                for _ in 0..*count {
360                    write!(f, "*")?;
361                }
362                Ok(())
363            }
364            FieldOperation::Method { name, .. } => {
365                write!(f, ".{}()", name)
366            }
367            FieldOperation::Nested { fields } => {
368                for field in fields {
369                    write!(f, ".{}", field)?;
370                }
371                Ok(())
372            }
373            FieldOperation::Index { index } => {
374                write!(f, "[{}]", quote::quote! { #index })
375            }
376            FieldOperation::Chained { operations } => {
377                for op in operations {
378                    write!(f, "{}", op)?;
379                }
380                Ok(())
381            }
382            FieldOperation::Combined {
383                deref_count,
384                operation,
385            } => {
386                for _ in 0..*deref_count {
387                    write!(f, "*")?;
388                }
389                write!(f, "{}", operation)
390            }
391        }
392    }
393}
394
395#[derive(Debug, Clone, Copy)]
396pub(crate) enum ComparisonOp {
397    Less,
398    LessEqual,
399    Greater,
400    GreaterEqual,
401    Equal,
402    NotEqual,
403}
404
405impl fmt::Display for ComparisonOp {
406    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
407        match self {
408            ComparisonOp::Less => write!(f, "<"),
409            ComparisonOp::LessEqual => write!(f, "<="),
410            ComparisonOp::Greater => write!(f, ">"),
411            ComparisonOp::GreaterEqual => write!(f, ">="),
412            ComparisonOp::Equal => write!(f, "=="),
413            ComparisonOp::NotEqual => write!(f, "!="),
414        }
415    }
416}
417
418/// Structural assertion macro for testing complex data structures.
419///
420/// This procedural macro generates efficient runtime assertions that check structural patterns
421/// against actual values, providing detailed error messages when assertions fail. The macro
422/// transforms pattern-based syntax into optimized comparison code at compile time.
423///
424/// See the [crate-level documentation](crate) for comprehensive guides and learning examples.
425/// This documentation serves as a complete specification reference.
426///
427/// # Syntax Specification
428///
429/// ```text
430/// assert_struct!(expression, TypePattern);
431///
432/// TypePattern ::= TypeName '{' FieldPatternList '}'
433///              | '_' '{' FieldPatternList '}'  // Wildcard pattern
434/// FieldPatternList ::= (FieldPattern ',')* ('..')?
435/// FieldPattern ::= FieldName ':' Pattern
436///              | FieldName FieldOperation ':' Pattern  
437/// FieldOperation ::= ('*')+ | ('.' Identifier '(' ArgumentList? ')')
438/// Pattern ::= Value | ComparisonPattern | RangePattern | RegexPattern
439///          | EnumPattern | TuplePattern | SlicePattern | NestedPattern
440/// ```
441///
442/// # Complete Pattern Reference
443///
444/// ## Basic Value Patterns
445///
446/// | Pattern | Syntax | Description | Constraints |
447/// |---------|--------|-------------|-------------|
448/// | **Exact Value** | `field: value` | Direct equality comparison | Must implement `PartialEq` |
449/// | **String Literal** | `field: "text"` | String comparison (no `.to_string()` needed) | String or &str fields |
450/// | **Explicit Equality** | `field: == value` | Same as exact value but explicit | Must implement `PartialEq` |
451/// | **Inequality** | `field: != value` | Not equal comparison | Must implement `PartialEq` |
452///
453/// ## Comparison Patterns  
454///
455/// | Pattern | Syntax | Description | Constraints |
456/// |---------|--------|-------------|-------------|
457/// | **Greater Than** | `field: > value` | Numeric greater than | Must implement `PartialOrd` |
458/// | **Greater Equal** | `field: >= value` | Numeric greater or equal | Must implement `PartialOrd` |
459/// | **Less Than** | `field: < value` | Numeric less than | Must implement `PartialOrd` |
460/// | **Less Equal** | `field: <= value` | Numeric less or equal | Must implement `PartialOrd` |
461///
462/// ## Range Patterns
463///
464/// | Pattern | Syntax | Description | Constraints |
465/// |---------|--------|-------------|-------------|  
466/// | **Inclusive Range** | `field: start..=end` | Value in inclusive range | Must implement `PartialOrd` |
467/// | **Exclusive Range** | `field: start..end` | Value in exclusive range | Must implement `PartialOrd` |
468/// | **Range From** | `field: start..` | Value greater or equal to start | Must implement `PartialOrd` |
469/// | **Range To** | `field: ..end` | Value less than end | Must implement `PartialOrd` |
470/// | **Range Full** | `field: ..` | Matches any value | No constraints |
471///
472/// ## String Pattern Matching
473///
474/// | Pattern | Syntax | Description | Constraints |
475/// |---------|--------|-------------|-------------|
476/// | **Regex Literal** | `field: =~ r"pattern"` | Regular expression match | Requires `regex` feature, `String`/`&str` |
477/// | **Like Trait** | `field: =~ expression` | Custom pattern matching | Must implement `Like<T>` |
478///
479/// ## Field Operations
480///
481/// | Operation | Syntax | Description | Constraints |
482/// |-----------|--------|-------------|-------------|
483/// | **Dereference** | `*field: pattern` | Dereference smart pointer | Must implement `Deref` |
484/// | **Multiple Deref** | `**field: pattern` | Multiple dereference | Must implement `Deref` (nested) |
485/// | **Method Call** | `field.method(): pattern` | Call method and match result | Method must exist and return compatible type |
486/// | **Method with Args** | `field.method(args): pattern` | Call method with arguments | Method must exist with compatible signature |
487/// | **Tuple Method** | `(index.method(): pattern, _)` | Method on tuple element | Valid index, method exists |
488///
489/// ## Enum Patterns
490///
491/// | Pattern | Syntax | Description | Constraints |
492/// |---------|--------|-------------|-------------|
493/// | **Option Some** | `field: Some(pattern)` | Match Some variant with inner pattern | `Option<T>` field |
494/// | **Option None** | `field: None` | Match None variant | `Option<T>` field |
495/// | **Result Ok** | `field: Ok(pattern)` | Match Ok variant with inner pattern | `Result<T, E>` field |
496/// | **Result Err** | `field: Err(pattern)` | Match Err variant with inner pattern | `Result<T, E>` field |
497/// | **Unit Variant** | `field: EnumType::Variant` | Match unit enum variant | Enum with unit variant |
498/// | **Tuple Variant** | `field: EnumType::Variant(patterns...)` | Match tuple enum variant | Enum with tuple variant |
499/// | **Struct Variant** | `field: EnumType::Variant { fields... }` | Match struct enum variant | Enum with struct variant |
500///
501/// ## Wildcard Struct Patterns
502///
503/// | Pattern | Syntax | Description | Constraints |
504/// |---------|--------|-------------|-------------|
505/// | **Wildcard Struct** | `value: _ { fields... }` | Match struct without naming type | Must use `..` for partial matching |
506/// | **Nested Wildcard** | `_ { field: _ { ... }, .. }` | Nested anonymous structs | Avoids importing nested types |
507///
508/// ## Collection Patterns
509///
510/// | Pattern | Syntax | Description | Constraints |
511/// |---------|--------|-------------|-------------|
512/// | **Exact Slice** | `field: [pattern, pattern, ...]` | Match exact slice elements | `Vec<T>` or slice |
513/// | **Partial Head** | `field: [pattern, ..]` | Match prefix elements | `Vec<T>` or slice |
514/// | **Partial Tail** | `field: [.., pattern]` | Match suffix elements | `Vec<T>` or slice |
515/// | **Head and Tail** | `field: [pattern, .., pattern]` | Match first and last | `Vec<T>` or slice |
516/// | **Empty Slice** | `field: []` | Match empty collection | `Vec<T>` or slice |
517///
518/// ## Tuple Patterns  
519///
520/// | Pattern | Syntax | Description | Constraints |
521/// |---------|--------|-------------|-------------|
522/// | **Exact Tuple** | `field: (pattern, pattern, ...)` | Match all tuple elements | Tuple type |
523/// | **Wildcard Element** | `field: (pattern, _, pattern)` | Ignore specific elements | Tuple type |
524/// | **Indexed Method** | `field: (0.method(): pattern, _)` | Method call on tuple element | Valid index |
525///
526/// # Parameters
527///
528/// - **`expression`**: Any expression that evaluates to a struct instance. The expression is
529///   borrowed, not consumed, so the value remains available after the assertion.
530/// - **`TypeName`**: The struct type name. Must exactly match the runtime type of the expression.
531/// - **`{ fields }`**: Pattern specification for struct fields. Can be partial (with `..`) or exhaustive.
532///
533/// # Runtime Behavior
534///
535/// ## Evaluation Semantics
536///
537/// - **Non-consuming**: The macro borrows the value, leaving it available after the assertion
538/// - **Expression evaluation**: The expression is evaluated exactly once before pattern matching
539/// - **Short-circuit evaluation**: Patterns are evaluated left-to-right, failing fast on first mismatch  
540/// - **Field order independence**: Fields can be specified in any order in the pattern
541/// - **Type requirements**: All fields must have types compatible with their patterns
542///
543/// ## Pattern Matching Rules
544///
545/// ### Exhaustive vs Partial Matching
546/// - **Without `..`**: All struct fields must be specified in the pattern (exhaustive)
547/// - **With `..`**: Only specified fields are checked (partial matching)
548/// - **Multiple `..`**: Compilation error - only one rest pattern allowed per struct
549///
550/// ### Field Operation Precedence
551/// Field operations are applied in left-to-right order:
552/// ```text
553/// **field.method().other_method(): pattern
554/// // Equivalent to: ((*(*field)).method()).other_method()
555/// ```
556///
557/// ### String Literal Handling
558/// - String literals (`"text"`) automatically work with `String` and `&str` fields
559/// - No `.to_string()` conversion needed in patterns
560/// - Comparison uses `PartialEq` implementation
561///
562/// # Panics
563///
564/// The macro panics (causing test failure) when:
565///
566/// ## Pattern Mismatches
567/// - **Value mismatch**: Expected value doesn't equal actual value
568/// - **Comparison failure**: Comparison operator condition fails (e.g., `>`, `<`)  
569/// - **Range mismatch**: Value outside specified range
570/// - **Enum variant mismatch**: Different enum variant than expected
571/// - **Collection length mismatch**: Slice pattern length differs from actual length
572/// - **None/Some mismatch**: Expected `Some` but got `None`, or vice versa
573/// - **Ok/Err mismatch**: Expected `Ok` but got `Err`, or vice versa
574///
575/// ## Method Call Failures
576/// - **Method panic**: Called method itself panics during execution
577/// - **Argument evaluation panic**: Method arguments panic during evaluation
578///
579/// ## Regex Failures (when `regex` feature enabled)
580/// - **Invalid regex**: Malformed regular expression pattern
581/// - **Regex evaluation panic**: Regex engine encounters error
582///
583/// ## Runtime Type Issues
584/// **Note**: Type mismatches are caught at compile time, not runtime.
585///
586/// # Compilation Errors
587///
588/// ## Field Validation
589/// - **Nonexistent field**: Field doesn't exist on the struct type
590/// - **Missing fields**: Required fields not specified (without `..`)  
591/// - **Duplicate fields**: Same field specified multiple times
592/// - **Invalid field operations**: Operations not supported by field type
593///
594/// ## Type Compatibility
595/// - **Type mismatch**: Pattern type incompatible with field type
596/// - **Trait requirements**: Field doesn't implement required traits (`PartialEq`, `PartialOrd`, etc.)
597/// - **Method signatures**: Method doesn't exist or has incompatible signature
598/// - **Deref constraints**: Field type doesn't implement `Deref` for dereference operations
599///
600/// ## Syntax Validation  
601/// - **Invalid syntax**: Malformed pattern syntax
602/// - **Invalid operators**: Unsupported operator for field type
603/// - **Invalid ranges**: Malformed range expressions
604/// - **Invalid regex syntax**: Invalid regex literal (when using raw strings)
605/// - **Multiple rest patterns**: More than one `..` in same struct pattern
606///
607/// ## Feature Requirements
608/// - **Missing regex feature**: Using `=~ r"pattern"` without `regex` feature enabled
609/// - **Like trait not implemented**: Using `=~ expr` where `Like` trait not implemented
610///
611/// # Edge Cases and Limitations
612///
613/// ## Method Call Constraints
614/// - **Return type compatibility**: Method return type must be compatible with pattern type
615/// - **Argument evaluation**: Method arguments are evaluated before the method call
616/// - **No generic method inference**: Generic methods may require explicit type annotations
617/// - **Tuple indexing bounds**: Tuple method calls require valid index at compile time
618///
619/// ## Collection Pattern Limitations
620/// - **Fixed length patterns**: Slice patterns without `..` require exact length match
621/// - **Nested pattern complexity**: Deeply nested slice patterns may impact compile time
622/// - **Memory usage**: Large literal slice patterns increase binary size
623///
624/// ## Smart Pointer Behavior
625/// - **Multiple deref levels**: Each `*` adds one deref level, must match pointer nesting
626/// - **Deref coercion**: Standard Rust deref coercion rules apply
627/// - **Ownership semantics**: Dereferencing borrows the pointed-to value
628///
629/// ## Performance Considerations
630/// - **Compile time**: Complex nested patterns increase compilation time  
631/// - **Runtime overhead**: Pattern matching is zero-cost for simple patterns
632/// - **Error message generation**: Error formatting only occurs on failure
633///
634/// # Feature Dependencies
635///
636/// ## Regex Feature (`regex`)
637/// - **Default**: Enabled by default
638/// - **Required for**: `=~ r"pattern"` syntax with string literals
639/// - **Disable with**: `default-features = false` in Cargo.toml
640/// - **Alternative**: Use `Like` trait with pre-compiled regex or custom patterns
641///
642/// ## Like Trait Extension
643/// - **No feature required**: Always available
644/// - **Custom implementations**: Implement `Like<T>` for custom pattern matching
645/// - **Regex integration**: Built-in implementations for regex when feature enabled
646///
647/// # Error Message Format
648///
649/// When assertions fail, the macro generates structured error messages with:
650///
651/// ## Error Components
652/// - **Error type**: Specific failure category (value mismatch, comparison failure, etc.)
653/// - **Field path**: Complete path to the failing field (e.g., `response.user.profile.age`)
654/// - **Source location**: File name and line number of the assertion  
655/// - **Actual value**: The value that was found
656/// - **Expected pattern**: The pattern that was expected to match
657/// - **Pattern context**: Visual representation showing where the failure occurred
658///
659/// ## Error Types
660/// - **value mismatch**: Direct equality comparison failed
661/// - **comparison mismatch**: Comparison operator condition failed (`>`, `<`, etc.)
662/// - **range mismatch**: Value outside specified range
663/// - **regex mismatch**: Regex pattern didn't match
664/// - **enum variant mismatch**: Wrong enum variant
665/// - **slice mismatch**: Collection length or element pattern failure
666/// - **method call error**: Method call or result pattern failure
667///
668/// ## Pattern Context Display
669/// Complex patterns show visual context with failure highlighting:
670/// ```text
671/// assert_struct! failed:
672///
673///    | Response { user: User { profile: Profile {
674/// comparison mismatch:
675///   --> `response.user.profile.age` (tests/api.rs:45)
676///    |         age: > 18,
677///    |              ^^^^^ actual: 17
678///    | } } }
679/// ```
680///
681/// ## Method Call Errors
682/// Method calls in field paths are clearly indicated:
683/// ```text
684/// comparison mismatch:
685///   --> `data.items.len()` (tests/collections.rs:23)
686///   actual: 3
687///   expected: > 5
688/// ```
689///
690/// # Quick Reference Examples
691///
692/// ```rust
693/// # use assert_struct::assert_struct;
694/// # #[derive(Debug)]
695/// # struct Example { value: i32, name: String, items: Vec<i32> }
696/// # let example = Example { value: 42, name: "test".to_string(), items: vec![1, 2] };
697/// // Basic pattern matching
698/// assert_struct!(example, Example {
699///     value: 42,                    // Exact equality
700///     name: != "other",             // Inequality  
701///     items.len(): >= 2,            // Method call with comparison
702///     ..                            // Partial matching
703/// });
704/// ```
705///
706/// # See Also
707///
708/// - **Learning Guide**: See the [crate-level documentation](crate) for comprehensive examples
709/// - **Real-World Examples**: Check the `examples/` directory for practical usage patterns
710/// - **Like Trait**: Implement custom pattern matching with the `Like` trait
711#[proc_macro]
712pub fn assert_struct(input: TokenStream) -> TokenStream {
713    // Parse the input
714    let assert = match parse::parse(input) {
715        Ok(assert) => assert,
716        Err(err) => return TokenStream::from(err.to_compile_error()),
717    };
718
719    // Expand to output code
720    let expanded = expand::expand(&assert);
721
722    TokenStream::from(expanded)
723}