1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
//! Procedural macro implementation for assert-struct.
//!
//! This crate provides the procedural macro implementation for the `assert-struct` crate.
//! Users should use the main `assert-struct` crate which re-exports this macro.
//!
//! # Architecture Overview
//!
//! The macro transformation happens in three phases:
//!
//! 1. **Parse** (`parse.rs`): Tokenize the macro input into a Pattern AST
//! 2. **Expand** (`expand.rs`): Transform patterns into assertion code
//! 3. **Execute**: Generated code runs the actual assertions
//!
//! # Key Design Decisions
//!
//! - **Pattern enum**: Unified abstraction for all pattern types (struct, tuple, slice, etc.)
//! - **Explicit patterns**: Require explicit operators (e.g., `Some(== my_var)` not `Some(my_var)`)
//! - **Dual-path optimization**: String literal regexes compile at expansion time
//! - **Native Rust syntax**: Use match expressions for ranges, slices, and enums
//!
//! See the main `assert-struct` crate for documentation and examples.
use TokenStream;
use Pattern;
// Root-level struct that tracks the assertion
/// Structural assertion macro for testing complex data structures.
///
/// This procedural macro generates efficient runtime assertions that check structural patterns
/// against actual values, providing detailed error messages when assertions fail. The macro
/// transforms pattern-based syntax into optimized comparison code at compile time.
///
/// See the [crate-level documentation](crate) for comprehensive guides and learning examples.
/// This documentation serves as a complete specification reference.
///
/// # Syntax Specification
///
/// ```text
/// assert_struct!(expression, TypePattern);
///
/// TypePattern ::= TypeName '{' FieldPatternList '}'
/// | '{' FieldPatternList '}' // Anonymous struct (always partial)
/// FieldPatternList ::= (FieldPattern ',')* ('..')?
/// FieldPattern ::= FieldName ':' Pattern
/// | FieldName FieldOperation ':' Pattern
/// FieldOperation ::= ('*')+ | ('.' Identifier '(' ArgumentList? ')')
/// Pattern ::= Value | ComparisonPattern | RangePattern | RegexPattern
/// | EnumPattern | TuplePattern | SlicePattern | NestedPattern
/// ```
///
/// # Complete Pattern Reference
///
/// ## Basic Value Patterns
///
/// | Pattern | Syntax | Description | Constraints |
/// |---------|--------|-------------|-------------|
/// | **Exact Value** | `field: value` | Direct equality comparison | Must implement `PartialEq` |
/// | **String Literal** | `field: "text"` | String comparison (no `.to_string()` needed) | String or &str fields |
/// | **Explicit Equality** | `field: == value` | Same as exact value but explicit | Must implement `PartialEq` |
/// | **Inequality** | `field: != value` | Not equal comparison | Must implement `PartialEq` |
///
/// ## Comparison Patterns
///
/// | Pattern | Syntax | Description | Constraints |
/// |---------|--------|-------------|-------------|
/// | **Greater Than** | `field: > value` | Numeric greater than | Must implement `PartialOrd` |
/// | **Greater Equal** | `field: >= value` | Numeric greater or equal | Must implement `PartialOrd` |
/// | **Less Than** | `field: < value` | Numeric less than | Must implement `PartialOrd` |
/// | **Less Equal** | `field: <= value` | Numeric less or equal | Must implement `PartialOrd` |
///
/// ## Range Patterns
///
/// | Pattern | Syntax | Description | Constraints |
/// |---------|--------|-------------|-------------|
/// | **Inclusive Range** | `field: start..=end` | Value in inclusive range | Must implement `PartialOrd` |
/// | **Exclusive Range** | `field: start..end` | Value in exclusive range | Must implement `PartialOrd` |
/// | **Range From** | `field: start..` | Value greater or equal to start | Must implement `PartialOrd` |
/// | **Range To** | `field: ..end` | Value less than end | Must implement `PartialOrd` |
/// | **Range Full** | `field: ..` | Matches any value | No constraints |
///
/// ## String Pattern Matching
///
/// | Pattern | Syntax | Description | Constraints |
/// |---------|--------|-------------|-------------|
/// | **Regex Literal** | `field: =~ r"pattern"` | Regular expression match | Requires `regex` feature, `String`/`&str` |
/// | **Like Trait** | `field: =~ expression` | Custom pattern matching | Must implement `Like<T>` |
///
/// ## Field Operations
///
/// | Operation | Syntax | Description | Constraints |
/// |-----------|--------|-------------|-------------|
/// | **Dereference** | `*field: pattern` | Dereference smart pointer | Must implement `Deref` |
/// | **Multiple Deref** | `**field: pattern` | Multiple dereference | Must implement `Deref` (nested) |
/// | **Method Call** | `field.method(): pattern` | Call method and match result | Method must exist and return compatible type |
/// | **Method with Args** | `field.method(args): pattern` | Call method with arguments | Method must exist with compatible signature |
/// | **Tuple Method** | `(index.method(): pattern, _)` | Method on tuple element | Valid index, method exists |
///
/// ## Enum Patterns
///
/// | Pattern | Syntax | Description | Constraints |
/// |---------|--------|-------------|-------------|
/// | **Option Some** | `field: Some(pattern)` | Match Some variant with inner pattern | `Option<T>` field |
/// | **Option None** | `field: None` | Match None variant | `Option<T>` field |
/// | **Result Ok** | `field: Ok(pattern)` | Match Ok variant with inner pattern | `Result<T, E>` field |
/// | **Result Err** | `field: Err(pattern)` | Match Err variant with inner pattern | `Result<T, E>` field |
/// | **Unit Variant** | `field: EnumType::Variant` | Match unit enum variant | Enum with unit variant |
/// | **Tuple Variant** | `field: EnumType::Variant(patterns...)` | Match tuple enum variant | Enum with tuple variant |
/// | **Struct Variant** | `field: EnumType::Variant { fields... }` | Match struct enum variant | Enum with struct variant |
///
/// ## Anonymous Struct Patterns
///
/// | Pattern | Syntax | Description | Constraints |
/// |---------|--------|-------------|-------------|
/// | **Anonymous Struct** | `value: { fields... }` | Match struct without naming type | Always partial; `..` never required |
/// | **Nested Anonymous** | `{ field: { ... } }` | Nested anonymous structs | Avoids importing nested types |
///
/// ## Collection Patterns
///
/// | Pattern | Syntax | Description | Constraints |
/// |---------|--------|-------------|-------------|
/// | **Exact Slice** | `field: [pattern, pattern, ...]` | Match exact slice elements | `Vec<T>` or slice |
/// | **Partial Head** | `field: [pattern, ..]` | Match prefix elements | `Vec<T>` or slice |
/// | **Partial Tail** | `field: [.., pattern]` | Match suffix elements | `Vec<T>` or slice |
/// | **Head and Tail** | `field: [pattern, .., pattern]` | Match first and last | `Vec<T>` or slice |
/// | **Empty Slice** | `field: []` | Match empty collection | `Vec<T>` or slice |
///
/// ## Tuple Patterns
///
/// | Pattern | Syntax | Description | Constraints |
/// |---------|--------|-------------|-------------|
/// | **Exact Tuple** | `field: (pattern, pattern, ...)` | Match all tuple elements | Tuple type |
/// | **Wildcard Element** | `field: (pattern, _, pattern)` | Ignore specific elements | Tuple type |
/// | **Indexed Method** | `field: (0.method(): pattern, _)` | Method call on tuple element | Valid index |
///
/// # Parameters
///
/// - **`expression`**: Any expression that evaluates to a struct instance. The expression is
/// borrowed, not consumed, so the value remains available after the assertion.
/// - **`TypeName`**: The struct type name. Must exactly match the runtime type of the expression.
/// - **`{ fields }`**: Pattern specification for struct fields. Can be partial (with `..`) or exhaustive.
///
/// # Runtime Behavior
///
/// ## Evaluation Semantics
///
/// - **Non-consuming**: The macro borrows the value, leaving it available after the assertion
/// - **Expression evaluation**: The expression is evaluated exactly once before pattern matching
/// - **Short-circuit evaluation**: Patterns are evaluated left-to-right, failing fast on first mismatch
/// - **Field order independence**: Fields can be specified in any order in the pattern
/// - **Type requirements**: All fields must have types compatible with their patterns
///
/// ## Pattern Matching Rules
///
/// ### Exhaustive vs Partial Matching
/// - **Without `..`**: All struct fields must be specified in the pattern (exhaustive)
/// - **With `..`**: Only specified fields are checked (partial matching)
/// - **Multiple `..`**: Compilation error - only one rest pattern allowed per struct
/// - **Anonymous structs (`{ ... }`)**: Always partial — `..` is never required and may be omitted
///
/// ### Field Operation Precedence
/// Field operations are applied in left-to-right order:
/// ```text
/// **field.method().other_method(): pattern
/// // Equivalent to: ((*(*field)).method()).other_method()
/// ```
///
/// ### String Literal Handling
/// - String literals (`"text"`) automatically work with `String` and `&str` fields
/// - No `.to_string()` conversion needed in patterns
/// - Comparison uses `PartialEq` implementation
///
/// # Panics
///
/// The macro panics (causing test failure) when:
///
/// ## Pattern Mismatches
/// - **Value mismatch**: Expected value doesn't equal actual value
/// - **Comparison failure**: Comparison operator condition fails (e.g., `>`, `<`)
/// - **Range mismatch**: Value outside specified range
/// - **Enum variant mismatch**: Different enum variant than expected
/// - **Collection length mismatch**: Slice pattern length differs from actual length
/// - **None/Some mismatch**: Expected `Some` but got `None`, or vice versa
/// - **Ok/Err mismatch**: Expected `Ok` but got `Err`, or vice versa
///
/// ## Method Call Failures
/// - **Method panic**: Called method itself panics during execution
/// - **Argument evaluation panic**: Method arguments panic during evaluation
///
/// ## Regex Failures (when `regex` feature enabled)
/// - **Invalid regex**: Malformed regular expression pattern
/// - **Regex evaluation panic**: Regex engine encounters error
///
/// ## Runtime Type Issues
/// **Note**: Type mismatches are caught at compile time, not runtime.
///
/// # Compilation Errors
///
/// ## Field Validation
/// - **Nonexistent field**: Field doesn't exist on the struct type
/// - **Missing fields**: Required fields not specified (without `..`)
/// - **Duplicate fields**: Same field specified multiple times
/// - **Invalid field operations**: Operations not supported by field type
///
/// ## Type Compatibility
/// - **Type mismatch**: Pattern type incompatible with field type
/// - **Trait requirements**: Field doesn't implement required traits (`PartialEq`, `PartialOrd`, etc.)
/// - **Method signatures**: Method doesn't exist or has incompatible signature
/// - **Deref constraints**: Field type doesn't implement `Deref` for dereference operations
///
/// ## Syntax Validation
/// - **Invalid syntax**: Malformed pattern syntax
/// - **Invalid operators**: Unsupported operator for field type
/// - **Invalid ranges**: Malformed range expressions
/// - **Invalid regex syntax**: Invalid regex literal (when using raw strings)
/// - **Multiple rest patterns**: More than one `..` in same struct pattern
///
/// ## Feature Requirements
/// - **Missing regex feature**: Using `=~ r"pattern"` without `regex` feature enabled
/// - **Like trait not implemented**: Using `=~ expr` where `Like` trait not implemented
///
/// # Edge Cases and Limitations
///
/// ## Method Call Constraints
/// - **Return type compatibility**: Method return type must be compatible with pattern type
/// - **Argument evaluation**: Method arguments are evaluated before the method call
/// - **No generic method inference**: Generic methods may require explicit type annotations
/// - **Tuple indexing bounds**: Tuple method calls require valid index at compile time
///
/// ## Collection Pattern Limitations
/// - **Fixed length patterns**: Slice patterns without `..` require exact length match
/// - **Nested pattern complexity**: Deeply nested slice patterns may impact compile time
/// - **Memory usage**: Large literal slice patterns increase binary size
///
/// ## Smart Pointer Behavior
/// - **Multiple deref levels**: Each `*` adds one deref level, must match pointer nesting
/// - **Deref coercion**: Standard Rust deref coercion rules apply
/// - **Ownership semantics**: Dereferencing borrows the pointed-to value
///
/// ## Performance Considerations
/// - **Compile time**: Complex nested patterns increase compilation time
/// - **Runtime overhead**: Pattern matching is zero-cost for simple patterns
/// - **Error message generation**: Error formatting only occurs on failure
///
/// # Feature Dependencies
///
/// ## Regex Feature (`regex`)
/// - **Default**: Enabled by default
/// - **Required for**: `=~ r"pattern"` syntax with string literals
/// - **Disable with**: `default-features = false` in Cargo.toml
/// - **Alternative**: Use `Like` trait with pre-compiled regex or custom patterns
///
/// ## Like Trait Extension
/// - **No feature required**: Always available
/// - **Custom implementations**: Implement `Like<T>` for custom pattern matching
/// - **Regex integration**: Built-in implementations for regex when feature enabled
///
/// # Error Message Format
///
/// When assertions fail, the macro generates structured error messages with:
///
/// ## Error Components
/// - **Error type**: Specific failure category (value mismatch, comparison failure, etc.)
/// - **Field path**: Complete path to the failing field (e.g., `response.user.profile.age`)
/// - **Source location**: File name and line number of the assertion
/// - **Actual value**: The value that was found
/// - **Expected pattern**: The pattern that was expected to match
/// - **Pattern context**: Visual representation showing where the failure occurred
///
/// ## Error Types
/// - **value mismatch**: Direct equality comparison failed
/// - **comparison mismatch**: Comparison operator condition failed (`>`, `<`, etc.)
/// - **range mismatch**: Value outside specified range
/// - **regex mismatch**: Regex pattern didn't match
/// - **enum variant mismatch**: Wrong enum variant
/// - **slice mismatch**: Collection length or element pattern failure
/// - **method call error**: Method call or result pattern failure
///
/// ## Pattern Context Display
/// Complex patterns show visual context with failure highlighting:
/// ```text
/// assert_struct! failed:
///
/// | Response { user: User { profile: Profile {
/// comparison mismatch:
/// --> `response.user.profile.age` (tests/api.rs:45)
/// | age: > 18,
/// | ^^^^^ actual: 17
/// | } } }
/// ```
///
/// ## Method Call Errors
/// Method calls in field paths are clearly indicated:
/// ```text
/// comparison mismatch:
/// --> `data.items.len()` (tests/collections.rs:23)
/// actual: 3
/// expected: > 5
/// ```
///
/// # Quick Reference Examples
///
/// ```rust
/// # use assert_struct::assert_struct;
/// # #[derive(Debug)]
/// # struct Example { value: i32, name: String, items: Vec<i32> }
/// # let example = Example { value: 42, name: "test".to_string(), items: vec![1, 2] };
/// // Basic pattern matching
/// assert_struct!(example, Example {
/// value: 42, // Exact equality
/// name: != "other", // Inequality
/// items.len(): >= 2, // Method call with comparison
/// .. // Partial matching
/// });
/// ```
///
/// # See Also
///
/// - **Learning Guide**: See the [crate-level documentation](crate) for comprehensive examples
/// - **Real-World Examples**: Check the `examples/` directory for practical usage patterns
/// - **Like Trait**: Implement custom pattern matching with the `Like` trait