@@ -9,10 +9,10 @@ use super::{make_callable_name, make_godot_fn};
9
9
use crate :: builtin:: { Callable , GString , Variant } ;
10
10
use crate :: classes:: object:: ConnectFlags ;
11
11
use crate :: meta;
12
- use crate :: meta:: FromGodot ;
12
+ use crate :: meta:: InParamTuple ;
13
13
use crate :: obj:: { bounds, Bounds , Gd , GodotClass , WithSignals } ;
14
+ use crate :: registry:: signal:: signal_receiver:: { IndirectSignalReceiver , SignalReceiver } ;
14
15
use crate :: registry:: signal:: { ToSignalObj , TypedSignal } ;
15
- use std:: fmt:: Debug ;
16
16
17
17
/// Builder for customizing signal connections.
18
18
///
@@ -137,172 +137,173 @@ where
137
137
}
138
138
}
139
139
140
- macro_rules! impl_builder_connect {
141
- ( $( #[ $attr: meta] ) ? $( $args: ident : $Ps: ident ) ,* ) => {
142
- $( #[ $attr] ) ?
143
- impl <C : WithSignals , $( $Ps: Debug + FromGodot + ' static ) ,* >
144
- ConnectBuilder <' _, ' _, C , ( $( $Ps, ) * ) > {
145
- /// Connect a non-member function (global function, associated function or closure).
146
- ///
147
- /// Example usages:
148
- /// ```ignore
149
- /// sig.builder().connect(Self::static_func);
150
- /// sig.builder().flags(ConnectFlags::DEFERRED).connect(global_func);
151
- /// sig.connect(|arg| { /* closure */ });
152
- /// ```
153
- ///
154
- /// # Related APIs
155
- /// - To connect to a method on the object that owns this signal, use [`connect_self_mut()`][Self::connect_self_mut] or
156
- /// [`connect_self_gd()`][Self::connect_self_gd].
157
- /// - To connect to methods on other objects, use [`connect_other_mut()`][Self::connect_other_mut] or
158
- /// [`connect_other_gd()`][Self::connect_other_gd].
159
- /// - If you need [`connect flags`](ConnectFlags), call [`flags()`](Self::flags) before this.
160
- /// - If you need cross-thread signals, use [`connect_sync()`](#method.connect_sync) instead (requires feature "experimental-threads").
161
- pub fn connect<F , R >( self , mut function: F )
162
- where
163
- F : FnMut ( $( $Ps) ,* ) -> R + ' static ,
164
- {
165
- let godot_fn = make_godot_fn( move |( $( $args, ) * ) : ( $( $Ps, ) * ) | {
166
- function( $( $args) ,* ) ;
167
- } ) ;
140
+ impl < C : WithSignals , Ps : InParamTuple + ' static > ConnectBuilder < ' _ , ' _ , C , Ps > {
141
+ /// Connect a non-member function (global function, associated function or closure).
142
+ ///
143
+ /// Example usages:
144
+ /// ```ignore
145
+ /// sig.builder().connect(Self::static_func);
146
+ /// sig.builder().flags(ConnectFlags::DEFERRED).connect(global_func);
147
+ /// sig.connect(|arg| { /* closure */ });
148
+ /// ```
149
+ ///
150
+ /// # Related APIs
151
+ /// - To connect to a method on the object that owns this signal, use [`connect_self_mut()`][Self::connect_self_mut] or
152
+ /// [`connect_self_gd()`][Self::connect_self_gd].
153
+ /// - To connect to methods on other objects, use [`connect_other_mut()`][Self::connect_other_mut] or
154
+ /// [`connect_other_gd()`][Self::connect_other_gd].
155
+ /// - If you need [`connect flags`](ConnectFlags), call [`flags()`](Self::flags) before this.
156
+ /// - If you need cross-thread signals, use [`connect_sync()`](#method.connect_sync) instead (requires feature "experimental-threads").
157
+ pub fn connect < F > ( self , mut function : F )
158
+ where
159
+ for < ' c_rcv > F : SignalReceiver < ( ) , Ps > ,
160
+ for < ' c_rcv > IndirectSignalReceiver < ' c_rcv , ( ) , Ps , F > : From < & ' c_rcv mut F > ,
161
+ {
162
+ let godot_fn = make_godot_fn ( move |args| {
163
+ IndirectSignalReceiver :: from ( & mut function)
164
+ . function ( )
165
+ . call ( ( ) , args) ;
166
+ } ) ;
168
167
169
- self . inner_connect_godot_fn:: <F >( godot_fn) ;
170
- }
168
+ self . inner_connect_godot_fn :: < F > ( godot_fn) ;
169
+ }
171
170
172
- /// Connect a method with `&mut self` as the first parameter (user classes only).
173
- ///
174
- /// # Related APIs
175
- /// - Use [`connect_self_gd()`][Self::connect_self_gd] to receive `Gd<Self>` instead and avoid implicit `bind_mut()` on emit. \
176
- /// For engine classes, `&mut self` is not supported at all.
177
- /// - To connect to methods on other objects, use [`connect_other_mut()`][Self::connect_other_mut].
178
- /// - If you need [connect flags](ConnectFlags), call [`flags()`](Self::flags) before this.
179
- /// - If you need cross-thread signals, use [`connect_sync()`](#method.connect_sync) instead (requires feature `experimental-threads`).
180
- pub fn connect_self_mut<F , R >( self , mut function: F )
181
- where
182
- C : Bounds <Declarer = bounds:: DeclUser >,
183
- F : FnMut ( & mut C , $( $Ps) ,* ) -> R + ' static ,
184
- {
185
- let mut gd = self . parent_sig. receiver_object( ) ;
171
+ /// Connect a method with `&mut self` as the first parameter (user classes only).
172
+ ///
173
+ /// # Related APIs
174
+ /// - Use [`connect_self_gd()`][Self::connect_self_gd] to receive `Gd<Self>` instead and avoid implicit `bind_mut()` on emit. \
175
+ /// For engine classes, `&mut self` is not supported at all.
176
+ /// - To connect to methods on other objects, use [`connect_other_mut()`][Self::connect_other_mut].
177
+ /// - If you need [connect flags](ConnectFlags), call [`flags()`](Self::flags) before this.
178
+ /// - If you need cross-thread signals, use [`connect_sync()`](#method.connect_sync) instead (requires feature `experimental-threads`).
179
+ pub fn connect_self_mut < F > ( self , mut function : F )
180
+ where
181
+ C : Bounds < Declarer = bounds:: DeclUser > ,
182
+ for < ' c_rcv > F : SignalReceiver < & ' c_rcv mut C , Ps > ,
183
+ for < ' c_rcv > IndirectSignalReceiver < ' c_rcv , & ' c_rcv mut C , Ps , F > : From < & ' c_rcv mut F > ,
184
+ {
185
+ let mut gd = self . parent_sig . receiver_object ( ) ;
186
186
187
- let godot_fn = make_godot_fn( move |( $( $args, ) * ) : ( $( $Ps, ) * ) | {
188
- let mut guard = Gd :: bind_mut( & mut gd) ;
189
- function( & mut * guard, $( $args) ,* ) ;
190
- } ) ;
187
+ let godot_fn = make_godot_fn ( move |args| {
188
+ let mut guard = Gd :: bind_mut ( & mut gd) ;
189
+ IndirectSignalReceiver :: from ( & mut function)
190
+ . function ( )
191
+ . call ( & mut * guard, args) ;
192
+ } ) ;
191
193
192
- self . inner_connect_godot_fn:: <F >( godot_fn) ;
193
- }
194
+ self . inner_connect_godot_fn :: < F > ( godot_fn) ;
195
+ }
194
196
195
- /// Connect a method with `&mut Gd<Self>` as the first parameter (user + engine classes).
196
- ///
197
- /// # Related APIs
198
- /// - If your class `C` is user-defined and you'd like to have an automatic `bind_mut()` and receive `&mut self`, then
199
- /// use [`connect_self_mut()`][Self::connect_self_mut] instead.
200
- /// - To connect to methods on other objects, use [`connect_other_gd()`][Self::connect_other_gd].
201
- /// - If you need [connect flags](ConnectFlags), call [`flags()`](Self::flags) before this.
202
- /// - If you need cross-thread signals, use [`connect_sync()`](#method.connect_sync) instead (requires feature `experimental-threads`).
203
- pub fn connect_self_gd<F , R >( self , mut function: F )
204
- where
205
- F : FnMut ( Gd <C >, $( $Ps) ,* ) -> R + ' static ,
206
- {
207
- let gd = self . parent_sig. receiver_object( ) ;
197
+ /// Connect a method with `&mut Gd<Self>` as the first parameter (user + engine classes).
198
+ ///
199
+ /// # Related APIs
200
+ /// - If your class `C` is user-defined and you'd like to have an automatic `bind_mut()` and receive `&mut self`, then
201
+ /// use [`connect_self_mut()`][Self::connect_self_mut] instead.
202
+ /// - To connect to methods on other objects, use [`connect_other_gd()`][Self::connect_other_gd].
203
+ /// - If you need [connect flags](ConnectFlags), call [`flags()`](Self::flags) before this.
204
+ /// - If you need cross-thread signals, use [`connect_sync()`](#method.connect_sync) instead (requires feature `experimental-threads`).
205
+ pub fn connect_self_gd < F > ( self , mut function : F )
206
+ where
207
+ F : SignalReceiver < Gd < C > , Ps > ,
208
+ for < ' c_rcv > IndirectSignalReceiver < ' c_rcv , Gd < C > , Ps , F > : From < & ' c_rcv mut F > ,
209
+ {
210
+ let gd = self . parent_sig . receiver_object ( ) ;
208
211
209
- let godot_fn = make_godot_fn( move |( $( $args, ) * ) : ( $( $Ps, ) * ) | {
210
- function( gd. clone( ) , $( $args) ,* ) ;
211
- } ) ;
212
+ let godot_fn = make_godot_fn ( move |args| {
213
+ IndirectSignalReceiver :: from ( & mut function)
214
+ . function ( )
215
+ . call ( gd. clone ( ) , args) ;
216
+ } ) ;
212
217
213
- self . inner_connect_godot_fn:: <F >( godot_fn) ;
214
- }
218
+ self . inner_connect_godot_fn :: < F > ( godot_fn) ;
219
+ }
215
220
216
- /// Connect a method with any `&mut OtherC` as the first parameter (user classes only).
217
- ///
218
- /// The parameter `object` can be of 2 different "categories":
219
- /// - Any `&Gd<OtherC>` (e.g.: `&Gd<Node>`, `&Gd<MyClass>`).
220
- /// - `&OtherC`, as long as `OtherC` is a user class that contains a `Base<T>` field (it implements the
221
- /// [`WithBaseField`](crate::obj::WithBaseField) trait).
222
- ///
223
- /// # Related APIs
224
- /// - Use [`connect_other_gd()`][Self::connect_other_gd] to receive `Gd<Self>` instead and avoid implicit `bind_mut()` on emit. \
225
- /// For engine classes, `&mut self` is not supported at all.
226
- /// - To connect to methods on the object that owns this signal, use [`connect_self_mut()`][Self::connect_self_mut].
227
- /// - If you need [connect flags](ConnectFlags), call [`flags()`](Self::flags) before this.
228
- /// - If you need cross-thread signals, use [`connect_sync()`](#method.connect_sync) instead (requires feature "experimental-threads").
229
- pub fn connect_other_mut<F , R , OtherC >( self , object: & impl ToSignalObj <OtherC >, mut method: F )
230
- where
231
- OtherC : GodotClass + Bounds <Declarer = bounds:: DeclUser >,
232
- F : FnMut ( & mut OtherC , $( $Ps) ,* ) -> R + ' static ,
233
- {
234
- let mut gd = object. to_signal_obj( ) ;
221
+ /// Connect a method with any `&mut OtherC` as the first parameter (user classes only).
222
+ ///
223
+ /// The parameter `object` can be of 2 different "categories":
224
+ /// - Any `&Gd<OtherC>` (e.g.: `&Gd<Node>`, `&Gd<MyClass>`).
225
+ /// - `&OtherC`, as long as `OtherC` is a user class that contains a `Base<T>` field (it implements the
226
+ /// [`WithBaseField`](crate::obj::WithBaseField) trait).
227
+ ///
228
+ /// # Related APIs
229
+ /// - Use [`connect_other_gd()`][Self::connect_other_gd] to receive `Gd<Self>` instead and avoid implicit `bind_mut()` on emit. \
230
+ /// For engine classes, `&mut self` is not supported at all.
231
+ /// - To connect to methods on the object that owns this signal, use [`connect_self_mut()`][Self::connect_self_mut].
232
+ /// - If you need [connect flags](ConnectFlags), call [`flags()`](Self::flags) before this.
233
+ /// - If you need cross-thread signals, use [`connect_sync()`](#method.connect_sync) instead (requires feature "experimental-threads").
234
+ pub fn connect_other_mut < F , OtherC > ( self , object : & impl ToSignalObj < OtherC > , mut method : F )
235
+ where
236
+ OtherC : GodotClass + Bounds < Declarer = bounds:: DeclUser > ,
237
+ for < ' c_rcv > F : SignalReceiver < & ' c_rcv mut OtherC , Ps > ,
238
+ for < ' c_rcv > IndirectSignalReceiver < ' c_rcv , & ' c_rcv mut OtherC , Ps , F > : From < & ' c_rcv mut F > ,
239
+ {
240
+ let mut gd = object. to_signal_obj ( ) ;
235
241
236
- let godot_fn = make_godot_fn( move |( $( $args, ) * ) : ( $( $Ps, ) * ) | {
237
- let mut guard = Gd :: bind_mut( & mut gd) ;
238
- method( & mut * guard, $( $args) ,* ) ;
239
- } ) ;
242
+ let godot_fn = make_godot_fn ( move |args| {
243
+ let mut guard = Gd :: bind_mut ( & mut gd) ;
244
+ IndirectSignalReceiver :: from ( & mut method)
245
+ . function ( )
246
+ . call ( & mut * guard, args) ;
247
+ } ) ;
240
248
241
- self . inner_connect_godot_fn:: <F >( godot_fn) ;
242
- }
249
+ self . inner_connect_godot_fn :: < F > ( godot_fn) ;
250
+ }
243
251
244
- /// Connect a method with any `&mut Gd<OtherC>` as the first parameter (user + engine classes).
245
- ///
246
- /// The parameter `object` can be of 2 different "categories":
247
- /// - Any `&Gd<OtherC>` (e.g.: `&Gd<Node>`, `&Gd<MyClass>`).
248
- /// - `&OtherC`, as long as `OtherC` is a user class that contains a `Base<T>` field (it implements the
249
- /// [`WithBaseField`](crate::obj::WithBaseField) trait).
250
- ///
251
- /// # Related APIs
252
- /// - To connect to methods on the object that owns this signal, use [`connect_self_gd()`][Self::connect_self_gd].
253
- /// - If you need [connect flags](ConnectFlags), call [`flags()`](Self::flags) before this.
254
- /// - If you need cross-thread signals, use [`connect_sync()`](#method.connect_sync) instead (requires feature "experimental-threads").
255
- pub fn connect_other_gd<F , R , OtherC >( self , object: & impl ToSignalObj <OtherC >, mut method: F )
256
- where
257
- OtherC : GodotClass ,
258
- F : FnMut ( Gd <OtherC >, $( $Ps) ,* ) -> R + ' static ,
259
- {
260
- let gd = object. to_signal_obj( ) ;
252
+ /// Connect a method with any `&mut Gd<OtherC>` as the first parameter (user + engine classes).
253
+ ///
254
+ /// The parameter `object` can be of 2 different "categories":
255
+ /// - Any `&Gd<OtherC>` (e.g.: `&Gd<Node>`, `&Gd<MyClass>`).
256
+ /// - `&OtherC`, as long as `OtherC` is a user class that contains a `Base<T>` field (it implements the
257
+ /// [`WithBaseField`](crate::obj::WithBaseField) trait).
258
+ ///
259
+ /// # Related APIs
260
+ /// - To connect to methods on the object that owns this signal, use [`connect_self_gd()`][Self::connect_self_gd].
261
+ /// - If you need [connect flags](ConnectFlags), call [`flags()`](Self::flags) before this.
262
+ /// - If you need cross-thread signals, use [`connect_sync()`](#method.connect_sync) instead (requires feature "experimental-threads").
263
+ pub fn connect_other_gd < F , OtherC > ( self , object : & impl ToSignalObj < OtherC > , mut method : F )
264
+ where
265
+ OtherC : GodotClass ,
266
+ F : SignalReceiver < Gd < OtherC > , Ps > ,
267
+ for < ' c_rcv > IndirectSignalReceiver < ' c_rcv , Gd < OtherC > , Ps , F > : From < & ' c_rcv mut F > ,
268
+ {
269
+ let gd = object. to_signal_obj ( ) ;
261
270
262
- let godot_fn = make_godot_fn( move |( $( $args, ) * ) : ( $( $Ps, ) * ) | {
263
- method( gd. clone( ) , $( $args) ,* ) ;
264
- } ) ;
271
+ let godot_fn = make_godot_fn ( move |args| {
272
+ IndirectSignalReceiver :: from ( & mut method)
273
+ . function ( )
274
+ . call ( gd. clone ( ) , args) ;
275
+ } ) ;
265
276
266
- self . inner_connect_godot_fn:: <F >( godot_fn) ;
267
- }
277
+ self . inner_connect_godot_fn :: < F > ( godot_fn) ;
278
+ }
268
279
269
- /// Connect to this signal using a thread-safe function, allows the signal to be called across threads.
270
- ///
271
- /// Requires `Send` + `Sync` bounds on the provided function `F`, and is only available for the `experimental-threads`
272
- /// Cargo feature.
273
- ///
274
- /// If you need [connect flags](ConnectFlags), call [`flags()`](Self::flags) before this.
275
- #[ cfg( feature = "experimental-threads" ) ]
276
- pub fn connect_sync<F , R >( self , mut function: F )
277
- where
278
- // Why both Send+Sync: closure can not only impact another thread (Sync), but it's also possible to share such Callables across threads
279
- // (Send) or even call them from multiple threads (Sync). We don't differentiate the fine-grained needs, it's either thread-safe or not.
280
- F : FnMut ( $( $Ps) ,* ) -> R + Send + Sync + ' static ,
281
- {
282
- let godot_fn = make_godot_fn( move |( $( $args, ) * ) : ( $( $Ps, ) * ) | {
283
- function( $( $args) ,* ) ;
284
- } ) ;
280
+ /// Connect to this signal using a thread-safe function, allows the signal to be called across threads.
281
+ ///
282
+ /// Requires `Send` + `Sync` bounds on the provided function `F`, and is only available for the `experimental-threads`
283
+ /// Cargo feature.
284
+ ///
285
+ /// If you need [connect flags](ConnectFlags), call [`flags()`](Self::flags) before this.
286
+ #[ cfg( feature = "experimental-threads" ) ]
287
+ pub fn connect_sync < F > ( self , mut function : F )
288
+ where
289
+ // Why both Send+Sync: closure can not only impact another thread (Sync), but it's also possible to share such Callables across threads
290
+ // (Send) or even call them from multiple threads (Sync). We don't differentiate the fine-grained needs, it's either thread-safe or not.
291
+ for < ' c_rcv > F : SignalReceiver < ( ) , Ps > + Send + Sync ,
292
+ for < ' c_rcv > IndirectSignalReceiver < ' c_rcv , ( ) , Ps , F > : From < & ' c_rcv mut F > ,
293
+ {
294
+ let godot_fn = make_godot_fn ( move |args| {
295
+ IndirectSignalReceiver :: from ( & mut function)
296
+ . function ( )
297
+ . call ( ( ) , args) ;
298
+ } ) ;
285
299
286
- let callable_name = match & self . data. callable_name {
287
- Some ( user_provided_name) => user_provided_name,
288
- None => & make_callable_name:: <F >( ) ,
289
- } ;
300
+ let callable_name = match & self . data . callable_name {
301
+ Some ( user_provided_name) => user_provided_name,
302
+ None => & make_callable_name :: < F > ( ) ,
303
+ } ;
290
304
291
- let callable = Callable :: from_sync_fn( callable_name, godot_fn) ;
292
- self . parent_sig. inner_connect_untyped( & callable, self . data. connect_flags) ;
293
- }
294
- }
295
- } ;
305
+ let callable = Callable :: from_sync_fn ( callable_name, godot_fn) ;
306
+ self . parent_sig
307
+ . inner_connect_untyped ( & callable, self . data . connect_flags ) ;
308
+ }
296
309
}
297
-
298
- impl_builder_connect ! ( #[ doc( hidden) ] ) ;
299
- impl_builder_connect ! ( #[ doc( hidden) ] arg0: P0 ) ;
300
- impl_builder_connect ! ( #[ doc( hidden) ] arg0: P0 , arg1: P1 ) ;
301
- impl_builder_connect ! ( arg0: P0 , arg1: P1 , arg2: P2 ) ;
302
- impl_builder_connect ! ( #[ doc( hidden) ] arg0: P0 , arg1: P1 , arg2: P2 , arg3: P3 ) ;
303
- impl_builder_connect ! ( #[ doc( hidden) ] arg0: P0 , arg1: P1 , arg2: P2 , arg3: P3 , arg4: P4 ) ;
304
- impl_builder_connect ! ( #[ doc( hidden) ] arg0: P0 , arg1: P1 , arg2: P2 , arg3: P3 , arg4: P4 , arg5: P5 ) ;
305
- impl_builder_connect ! ( #[ doc( hidden) ] arg0: P0 , arg1: P1 , arg2: P2 , arg3: P3 , arg4: P4 , arg5: P5 , arg6: P6 ) ;
306
- impl_builder_connect ! ( #[ doc( hidden) ] arg0: P0 , arg1: P1 , arg2: P2 , arg3: P3 , arg4: P4 , arg5: P5 , arg6: P6 , arg7: P7 ) ;
307
- impl_builder_connect ! ( #[ doc( hidden) ] arg0: P0 , arg1: P1 , arg2: P2 , arg3: P3 , arg4: P4 , arg5: P5 , arg6: P6 , arg7: P7 , arg8: P8 ) ;
308
- impl_builder_connect ! ( #[ doc( hidden) ] arg0: P0 , arg1: P1 , arg2: P2 , arg3: P3 , arg4: P4 , arg5: P5 , arg6: P6 , arg7: P7 , arg8: P8 , arg9: P9 ) ;
0 commit comments