@@ -4,15 +4,14 @@ use crate::{
44} ;
55use darling:: { ast:: NestedMeta , Error , FromMeta } ;
66use heck:: ToSnakeCase ;
7- use itertools:: Itertools as _;
87use proc_macro2:: Span ;
98use proc_macro2:: TokenStream as TokenStream2 ;
109use quote:: { format_ident, quote} ;
1110use stellar_xdr:: curr:: {
1211 ScSpecEntry , ScSpecEventDataFormat , ScSpecEventParamLocationV0 , ScSpecEventParamV0 ,
1312 ScSpecEventV0 , ScSymbol , StringM , WriteXdr ,
1413} ;
15- use syn:: { parse2, spanned:: Spanned , Data , DeriveInput , Fields , LitStr , Path } ;
14+ use syn:: { ext :: IdentExt as _ , parse2, spanned:: Spanned , Data , DeriveInput , Fields , LitStr , Path } ;
1615
1716#[ derive( Debug , FromMeta ) ]
1817struct ContractEventArgs {
@@ -88,7 +87,7 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt
8887
8988 // Check event name length
9089 const EVENT_NAME_LENGTH : u32 = 32 ;
91- let event_name = input. ident . to_string ( ) ;
90+ let event_name = input. ident . unraw ( ) . to_string ( ) ;
9291 let event_name_len = event_name. len ( ) ;
9392 let event_name: StringM < EVENT_NAME_LENGTH > = errors
9493 . handle ( event_name. try_into ( ) . map_err ( |_| {
@@ -102,7 +101,7 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt
102101 let prefix_topics = if let Some ( prefix_topics) = & args. topics {
103102 prefix_topics. iter ( ) . map ( |t| t. value ( ) ) . collect ( )
104103 } else {
105- vec ! [ input. ident. to_string( ) . to_snake_case( ) ]
104+ vec ! [ input. ident. unraw ( ) . to_string( ) . to_snake_case( ) ]
106105 } ;
107106
108107 let fields =
@@ -127,8 +126,11 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt
127126 // Collect field types for SpecShakingMarker
128127 let field_types: Vec < _ > = fields. iter ( ) . map ( |f| & f. ty ) . collect ( ) ;
129128
130- // Map each field of the struct to a spec for a param.
131- let params = fields
129+ // Map each field of the struct to a spec for a param, keeping the original Ident
130+ // alongside so it can still be used for `self.#ident` field access in the generated
131+ // code (raw identifiers like `r#type` need to stay raw for Rust, while the spec name
132+ // is the unraw form).
133+ let params_with_idents = fields
132134 . iter ( )
133135 . map ( |field| {
134136 let ident = field. ident . as_ref ( ) . unwrap ( ) ;
@@ -140,7 +142,7 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt
140142 } ;
141143 let doc = docs_from_attrs ( & field. attrs ) ;
142144 const NAME_LENGTH : u32 = 30 ;
143- let name = ident. to_string ( ) ;
145+ let name = ident. unraw ( ) . to_string ( ) ;
144146 let name_len = name. len ( ) ;
145147 let name: StringM < NAME_LENGTH > = errors
146148 . handle ( name. try_into ( ) . map_err ( |_| {
@@ -153,12 +155,15 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt
153155 let type_ = errors
154156 . handle_in ( || Ok ( map_type ( & field. ty , true , false ) ?) )
155157 . unwrap_or_default ( ) ;
156- ScSpecEventParamV0 {
157- location,
158- doc,
159- name,
160- type_,
161- }
158+ (
159+ ident. clone ( ) ,
160+ ScSpecEventParamV0 {
161+ location,
162+ doc,
163+ name,
164+ type_,
165+ } ,
166+ )
162167 } )
163168 . collect :: < Vec < _ > > ( ) ;
164169
@@ -183,9 +188,9 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt
183188 . collect :: < Vec < _ > > ( )
184189 . try_into ( )
185190 . unwrap ( ) ,
186- params : params
191+ params : params_with_idents
187192 . iter ( )
188- . map ( |p | p. clone ( ) )
193+ . map ( |( _ , p ) | p. clone ( ) )
189194 . collect :: < Vec < _ > > ( )
190195 . try_into ( )
191196 . unwrap ( ) ,
@@ -195,7 +200,7 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt
195200 let spec_xdr_len = spec_xdr. len ( ) ;
196201 let spec_ident = format_ident ! (
197202 "__SPEC_XDR_EVENT_{}" ,
198- input. ident. to_string( ) . to_uppercase( )
203+ input. ident. unraw ( ) . to_string( ) . to_uppercase( )
199204 ) ;
200205 let spec_shaking_call = if export && spec_shaking_v2_enabled ( ) {
201206 Some ( quote ! { <Self as #path:: SpecShakingMarker >:: spec_shaking_marker( ) ; } )
@@ -239,10 +244,10 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt
239244 & LitStr :: new ( & t, Span :: call_site ( ) ) ,
240245 )
241246 } ) ;
242- let topic_idents = params
247+ let topic_idents = params_with_idents
243248 . iter ( )
244- . filter ( |p | p. location == ScSpecEventParamLocationV0 :: TopicList )
245- . map ( |p| format_ident ! ( "{}" , p . name . to_string ( ) ) )
249+ . filter ( |( _ , p ) | p. location == ScSpecEventParamLocationV0 :: TopicList )
250+ . map ( |( ident , _ ) | ident . clone ( ) )
246251 . collect :: < Vec < _ > > ( ) ;
247252 let topics_to_vec_val = quote ! {
248253 use #path:: IntoVal ;
@@ -253,14 +258,14 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt
253258 } ;
254259
255260 // Prepare Data Conversion to Val.
256- let data_params = params
261+ let data_params = params_with_idents
257262 . iter ( )
258- . filter ( |p | p. location == ScSpecEventParamLocationV0 :: Data )
263+ . filter ( |( _ , p ) | p. location == ScSpecEventParamLocationV0 :: Data )
259264 . collect :: < Vec < _ > > ( ) ;
260265 let data_params_count = data_params. len ( ) ;
261266 let data_idents = data_params
262267 . iter ( )
263- . map ( |p| format_ident ! ( "{}" , p . name . to_string ( ) ) )
268+ . map ( |( ident , _ ) | ident . clone ( ) )
264269 . collect :: < Vec < _ > > ( ) ;
265270 let data_to_val = match args. data_format {
266271 DataFormat :: SingleValue if data_params_count == 0 => quote ! {
@@ -288,15 +293,18 @@ fn derive_impls(args: &ContractEventArgs, input: &DeriveInput) -> Result<TokenSt
288293 ) . into_val( env)
289294 } ,
290295 DataFormat :: Map => {
291- // Must be sorted for map_new_from_slices
292- let data_idents_sorted = data_params
296+ // Must be sorted for map_new_from_slices. Sort by the spec name (the
297+ // Soroban-facing Symbol string), and carry the original Ident alongside so
298+ // that `self.#ident` still uses the raw form where needed.
299+ let mut data_params_sorted = data_params. clone ( ) ;
300+ data_params_sorted. sort_by_key ( |( _, p) | p. name . to_string ( ) ) ;
301+ let data_idents_sorted = data_params_sorted
293302 . iter ( )
294- . sorted_by_key ( |p| p. name . to_string ( ) )
295- . map ( |p| format_ident ! ( "{}" , p. name. to_string( ) ) )
303+ . map ( |( ident, _) | ident. clone ( ) )
296304 . collect :: < Vec < _ > > ( ) ;
297- let data_strs_sorted = data_idents_sorted
305+ let data_strs_sorted = data_params_sorted
298306 . iter ( )
299- . map ( |i| i . to_string ( ) )
307+ . map ( |( _ , p ) | p . name . to_string ( ) )
300308 . collect :: < Vec < _ > > ( ) ;
301309 quote ! {
302310 use #path:: { EnvBase , IntoVal , unwrap:: UnwrapInfallible } ;
0 commit comments