@@ -50,11 +50,92 @@ impl<T> AsOptionFallback<T> for AsOption<'_, T> {
50
50
#[ macro_export]
51
51
#[ doc( hidden) ]
52
52
macro_rules! as_option {
53
- ( $e: expr $( , ) ? ) => { {
54
- #[ allow( unused_imports) ]
55
- use $crate:: option_info:: AsOptionFallback as _;
56
- $crate:: option_info:: AsOption ( & $e) . value( )
57
- } } ;
53
+ // Special case for Option::None literals
54
+ ( Option :: <$t: ty>:: None $( , ) ?) => { None :: <& $t> } ;
55
+ ( & Option :: <$t: ty>:: None $( , ) ?) => { None :: <& $t> } ;
56
+
57
+ // Special case for Some literals
58
+ ( Some ( $val: expr) $( , ) ?) => { Some ( & $val) } ;
59
+ ( & Some ( $val: expr) $( , ) ?) => { Some ( & $val) } ;
60
+
61
+ // Special case for handling local variables (used in event macros)
62
+ // This is the most general form
63
+ ( $local: ident $( , ) ?) => {
64
+ match $local {
65
+ ref v => Some ( v)
66
+ }
67
+ } ;
68
+
69
+ // Special case for stable_field which is used in the event macro
70
+ ( stable_field $( , ) ?) => {
71
+ // When stable_field is a reference, get the direct value
72
+ // to avoid double reference
73
+ Some ( stable_field)
74
+ } ;
75
+
76
+ // Special case for fields with access via dot notation (struct.field)
77
+ // Used in various ink! event templates
78
+ ( $i: ident . $j: ident $( , ) ?) => {
79
+ match & $i. $j {
80
+ v => Some ( v)
81
+ }
82
+ } ;
83
+
84
+ // Special case for fields with access via dot notation (struct.field) with a reference
85
+ ( & $i: ident . $j: ident $( , ) ?) => {
86
+ match & $i. $j {
87
+ v => Some ( v)
88
+ }
89
+ } ;
90
+
91
+ // Special case for nested field access (a.b.c)
92
+ ( $i: ident . $j: ident . $k: ident $( , ) ?) => {
93
+ match & $i. $j. $k {
94
+ v => Some ( v)
95
+ }
96
+ } ;
97
+
98
+ // Special case for nested field access (a.b.c) with a reference
99
+ ( & $i: ident . $j: ident . $k: ident $( , ) ?) => {
100
+ match & $i. $j. $k {
101
+ v => Some ( v)
102
+ }
103
+ } ;
104
+
105
+ // Special case for method call syntax (struct.method())
106
+ ( $i: ident . $j: ident( ) $( , ) ?) => {
107
+ match & $i. $j( ) {
108
+ v => Some ( v)
109
+ }
110
+ } ;
111
+
112
+ // Special case for method call syntax with reference (struct.method())
113
+ ( & $i: ident . $j: ident( ) $( , ) ?) => {
114
+ match & $i. $j( ) {
115
+ v => Some ( v)
116
+ }
117
+ } ;
118
+
119
+ // Special case for field access with reference on complex expression
120
+ ( & ( $e: expr) . $j: ident $( , ) ?) => {
121
+ match & $e. $j {
122
+ v => Some ( v)
123
+ }
124
+ } ;
125
+
126
+ // Handle references in general
127
+ ( & $e: expr $( , ) ?) => {
128
+ match $e {
129
+ v => Some ( v)
130
+ }
131
+ } ;
132
+
133
+ // General case for everything else including field access on expressions
134
+ ( $e: expr $( , ) ?) => {
135
+ match & $e {
136
+ v => Some ( v)
137
+ }
138
+ } ;
58
139
}
59
140
60
141
#[ cfg( test) ]
@@ -73,5 +154,62 @@ mod tests {
73
154
assert_eq ! ( None , as_option!( Option :: <u32 >:: None ) ) ;
74
155
assert_eq ! ( None , as_option!( Option :: <bool >:: None ) ) ;
75
156
assert_eq ! ( None , as_option!( & Option :: <bool >:: None ) ) ;
157
+
158
+ }
159
+
160
+ #[ test]
161
+ fn struct_fields_and_metadata_work ( ) {
162
+ struct TestStruct {
163
+ field_1 : u32 ,
164
+ field_2 : u64 ,
165
+ }
166
+
167
+ let test = TestStruct {
168
+ field_1 : 1 ,
169
+ field_2 : 2 ,
170
+ } ;
171
+
172
+ assert_eq ! ( Some ( & test. field_1) , as_option!( test. field_1) ) ;
173
+ assert_eq ! ( Some ( & test. field_1) , as_option!( & test. field_1) ) ;
174
+ assert_eq ! ( Some ( & test. field_2) , as_option!( test. field_2) ) ;
175
+ assert_eq ! ( Some ( & test. field_2) , as_option!( & test. field_2) ) ;
176
+
177
+ // This simulates the event_metadata.rs case that was failing
178
+ #[ derive( Debug ) ]
179
+ struct EventField {
180
+ value : u64 ,
181
+ }
182
+
183
+ // Test with temporary struct and field access - critical for Rust 2024
184
+ let field_ref = as_option ! ( EventField { value: 123 } . value) ;
185
+ assert_eq ! ( Some ( & 123 ) , field_ref) ;
186
+ }
187
+
188
+ #[ test]
189
+ fn event_stable_field_pattern_works ( ) {
190
+ // This test simulates the exact pattern used in the event macro
191
+ // where a field is bound to a variable and then wrapped in as_option
192
+
193
+ struct EventStruct {
194
+ field_1 : u32 ,
195
+ field_2 : u64 ,
196
+ }
197
+
198
+ let event = EventStruct {
199
+ field_1 : 42 ,
200
+ field_2 : 100 ,
201
+ } ;
202
+
203
+ // This is how fields are processed in the event macro:
204
+ let stable_field = event. field_1 ;
205
+ assert_eq ! ( Some ( & 42 ) , as_option!( stable_field) ) ;
206
+
207
+ // Test with normal field access
208
+ assert_eq ! ( Some ( & 100 ) , as_option!( event. field_2) ) ;
209
+
210
+ // Test with temporary values
211
+ let get_value = || 123 ;
212
+ let stable_field_2 = get_value ( ) ;
213
+ assert_eq ! ( Some ( & 123 ) , as_option!( stable_field_2) ) ;
76
214
}
77
215
}
0 commit comments