@@ -64,8 +64,17 @@ struct FuncAttr {
6464
6565// ----------------------------------------------------------------------------------------------------------------------------------------------
6666
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+
6773/// 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 > {
6978 let class_name = util:: validate_impl ( & impl_block, None , "godot_api" ) ?;
7079 let class_name_obj = util:: class_name_obj ( & class_name) ;
7180 let prv = quote ! { :: godot:: private } ;
@@ -93,38 +102,98 @@ pub fn transform_inherent_impl(mut impl_block: venial::Impl) -> ParseResult<Toke
93102
94103 let constant_registration = make_constant_registration ( consts, & class_name, & class_name_obj) ?;
95104
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( ||{
98111
99- impl :: godot:: obj:: cap:: ImplementsGodotApi for #class_name {
100- fn __register_methods( ) {
101112 #( #method_registrations ) *
102113 #( #signal_registrations ) *
103- }
104114
105- fn __register_constants( ) {
106- #constant_registration
107- }
115+ } ) ;
116+ #constants_storage_name. lock( ) . unwrap( ) . push( ||{
108117
109- #rpc_registrations
110- }
118+ #constant_registration
111119
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+ } ) ;
124121 } ) ;
125122 } ;
126123
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+ }
128197}
129198
130199fn process_godot_fns (
0 commit comments