@@ -64,8 +64,17 @@ struct FuncAttr {
64
64
65
65
// ----------------------------------------------------------------------------------------------------------------------------------------------
66
66
67
+ pub struct InherentImplAttr {
68
+ /// For implementation reasons, there can be a single 'primary' impl block and 0 or more 'secondary' impl blocks.
69
+ /// For now this is controlled by a key in the the 'godot_api' attribute
70
+ pub secondary : bool ,
71
+ }
72
+
67
73
/// Codegen for `#[godot_api] impl MyType`
68
- pub fn transform_inherent_impl ( mut impl_block : venial:: Impl ) -> ParseResult < TokenStream > {
74
+ pub fn transform_inherent_impl (
75
+ meta : InherentImplAttr ,
76
+ mut impl_block : venial:: Impl ,
77
+ ) -> ParseResult < TokenStream > {
69
78
let class_name = util:: validate_impl ( & impl_block, None , "godot_api" ) ?;
70
79
let class_name_obj = util:: class_name_obj ( & class_name) ;
71
80
let prv = quote ! { :: godot:: private } ;
@@ -93,38 +102,98 @@ pub fn transform_inherent_impl(mut impl_block: venial::Impl) -> ParseResult<Toke
93
102
94
103
let constant_registration = make_constant_registration ( consts, & class_name, & class_name_obj) ?;
95
104
96
- let result = quote ! {
97
- #impl_block
105
+ let method_storage_name = format_ident ! ( "__registration_methods_{class_name}" ) ;
106
+ let constants_storage_name = format_ident ! ( "__registration_constants_{class_name}" ) ;
107
+
108
+ let fill_storage = quote ! {
109
+ :: godot:: sys:: plugin_execute_pre_main!( {
110
+ #method_storage_name. lock( ) . unwrap( ) . push( ||{
98
111
99
- impl :: godot:: obj:: cap:: ImplementsGodotApi for #class_name {
100
- fn __register_methods( ) {
101
112
#( #method_registrations ) *
102
113
#( #signal_registrations ) *
103
- }
104
114
105
- fn __register_constants( ) {
106
- #constant_registration
107
- }
115
+ } ) ;
116
+ #constants_storage_name. lock( ) . unwrap( ) . push( ||{
108
117
109
- #rpc_registrations
110
- }
118
+ #constant_registration
111
119
112
- :: godot:: sys:: plugin_add!( __GODOT_PLUGIN_REGISTRY in #prv; #prv:: ClassPlugin {
113
- class_name: #class_name_obj,
114
- item: #prv:: PluginItem :: InherentImpl ( #prv:: InherentImpl {
115
- register_methods_constants_fn: #prv:: ErasedRegisterFn {
116
- raw: #prv:: callbacks:: register_user_methods_constants:: <#class_name>,
117
- } ,
118
- register_rpcs_fn: Some ( #prv:: ErasedRegisterRpcsFn {
119
- raw: #prv:: callbacks:: register_user_rpcs:: <#class_name>,
120
- } ) ,
121
- #docs
122
- } ) ,
123
- init_level: <#class_name as :: godot:: obj:: GodotClass >:: INIT_LEVEL ,
120
+ } ) ;
124
121
} ) ;
125
122
} ;
126
123
127
- Ok ( result)
124
+ if !meta. secondary {
125
+ // We are the primary `impl` block.
126
+
127
+ let storage = quote ! {
128
+ #[ used]
129
+ #[ allow( non_upper_case_globals) ]
130
+ #[ doc( hidden) ]
131
+ static #method_storage_name: std:: sync:: Mutex <Vec <fn ( ) >> = std:: sync:: Mutex :: new( Vec :: new( ) ) ;
132
+
133
+ #[ used]
134
+ #[ allow( non_upper_case_globals) ]
135
+ #[ doc( hidden) ]
136
+ static #constants_storage_name: std:: sync:: Mutex <Vec <fn ( ) >> = std:: sync:: Mutex :: new( Vec :: new( ) ) ;
137
+ } ;
138
+
139
+ let trait_impl = quote ! {
140
+ impl :: godot:: obj:: cap:: ImplementsGodotApi for #class_name {
141
+ fn __register_methods( ) {
142
+ let guard = #method_storage_name. lock( ) . unwrap( ) ;
143
+ for f in guard. iter( ) {
144
+ f( ) ;
145
+ }
146
+ }
147
+
148
+ fn __register_constants( ) {
149
+ let guard = #constants_storage_name. lock( ) . unwrap( ) ;
150
+ for f in guard. iter( ) {
151
+ f( ) ;
152
+ }
153
+ }
154
+
155
+ #rpc_registrations
156
+ }
157
+ } ;
158
+
159
+ let class_registration = quote ! {
160
+
161
+ :: godot:: sys:: plugin_add!( __GODOT_PLUGIN_REGISTRY in #prv; #prv:: ClassPlugin {
162
+ class_name: #class_name_obj,
163
+ item: #prv:: PluginItem :: InherentImpl ( #prv:: InherentImpl {
164
+ register_methods_constants_fn: #prv:: ErasedRegisterFn {
165
+ raw: #prv:: callbacks:: register_user_methods_constants:: <#class_name>,
166
+ } ,
167
+ register_rpcs_fn: Some ( #prv:: ErasedRegisterRpcsFn {
168
+ raw: #prv:: callbacks:: register_user_rpcs:: <#class_name>,
169
+ } ) ,
170
+ #docs
171
+ } ) ,
172
+ init_level: <#class_name as :: godot:: obj:: GodotClass >:: INIT_LEVEL ,
173
+ } ) ;
174
+
175
+ } ;
176
+
177
+ let result = quote ! {
178
+ #impl_block
179
+ #storage
180
+ #trait_impl
181
+ #fill_storage
182
+ #class_registration
183
+ } ;
184
+
185
+ Ok ( result)
186
+ } else {
187
+ // We are in a secondary `impl` block, so most of the work has already been done
188
+ // and we just need to add out registration functions in the storage defined by the primary `impl` block.
189
+
190
+ let result = quote ! {
191
+ #impl_block
192
+ #fill_storage
193
+ } ;
194
+
195
+ Ok ( result)
196
+ }
128
197
}
129
198
130
199
fn process_godot_fns (
0 commit comments