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