@@ -50,11 +50,92 @@ impl<T> AsOptionFallback<T> for AsOption<'_, T> {
5050#[ macro_export]
5151#[ doc( hidden) ]
5252macro_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+ } ;
58139}
59140
60141#[ cfg( test) ]
@@ -73,5 +154,62 @@ mod tests {
73154 assert_eq ! ( None , as_option!( Option :: <u32 >:: None ) ) ;
74155 assert_eq ! ( None , as_option!( Option :: <bool >:: None ) ) ;
75156 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) ) ;
76214 }
77215}
0 commit comments