5
5
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
6
*/
7
7
8
- // Maybe move this to builtin::functional module?
9
-
10
8
use crate :: builtin:: { Callable , GString , Variant } ;
11
9
use crate :: classes:: object:: ConnectFlags ;
12
10
use crate :: obj:: { bounds, Bounds , Gd , GodotClass , WithBaseField } ;
13
- use crate :: registry:: functional :: { AsFunc , ConnectBuilder , ParamTuple } ;
11
+ use crate :: registry:: signal :: { ConnectBuilder , SignalReceiver } ;
14
12
use crate :: { classes, meta} ;
15
13
use std:: borrow:: Cow ;
16
14
use std:: marker:: PhantomData ;
17
15
16
+ /// Links to a Godot object, either via reference (for `&mut self` uses) or via `Gd`.
18
17
#[ doc( hidden) ]
19
18
pub enum ObjectRef < ' a , C : GodotClass > {
20
- /// Helpful for emit: reuse `&self` from within the `impl` block, goes through `base ()` re-borrowing and thus allows re-entrant calls
19
+ /// Helpful for emit: reuse `&mut self` from within the `impl` block, goes through `base_mut ()` re-borrowing and thus allows re-entrant calls
21
20
/// through Godot.
22
21
Internal { obj_mut : & ' a mut C } ,
23
22
@@ -46,15 +45,38 @@ where
46
45
47
46
// ----------------------------------------------------------------------------------------------------------------------------------------------
48
47
48
+ /// Type-safe version of a Godot signal.
49
+ ///
50
+ /// Short-lived type, only valid in the scope of its surrounding object type `C`, for lifetime `'c`. The generic argument `Ps` represents
51
+ /// the parameters of the signal, thus ensuring the type safety.
52
+ ///
53
+ /// The [`WithSignals::signals()`][crate::obj::WithSignals::signals] collection returns multiple signals with distinct, code-generated types,
54
+ /// but they all implement `Deref` and `DerefMut` to `TypedSignal`. This allows you to either use the concrete APIs of the generated types,
55
+ /// or the more generic ones of `TypedSignal`.
56
+ ///
57
+ /// # Connecting a signal to a receiver
58
+ /// Receiver functions are functions that are called when a signal is emitted. You can connect a signal in many different ways:
59
+ /// - [`connect()`][Self::connect] for global functions, associated functions or closures.
60
+ /// - [`connect_self()`][Self::connect_self] for methods with `&mut self` as the first parameter.
61
+ /// - [`connect_obj()`][Self::connect_obj] for methods with any `Gd<T>` (not `self`) as the first parameter.
62
+ /// - [`connect_builder()`][Self::connect_builder] for more complex setups.
63
+ ///
64
+ /// # Emitting a signal
65
+ /// Code-generated signal types provide a method `emit(...)`, which adopts the names and types of the `#[signal]` parameter list.
66
+ /// In most cases, that's the method you are looking for.
67
+ ///
68
+ /// For generic use, you can also use [`emit_tuple()`][Self::emit_tuple], which does not provide parameter names.
69
+ ///
70
+ /// # More information
71
+ /// See the [Signals](https://godot-rust.github.io/book/register/signals.html) chapter in the book for a detailed introduction and examples.
49
72
pub struct TypedSignal < ' c , C : GodotClass , Ps > {
50
- //signal: Signal,
51
73
/// In Godot, valid signals (unlike funcs) are _always_ declared in a class and become part of each instance. So there's always an object.
52
74
owner : ObjectRef < ' c , C > ,
53
75
name : Cow < ' static , str > ,
54
76
_signature : PhantomData < Ps > ,
55
77
}
56
78
57
- impl < ' c , C : WithBaseField , Ps : ParamTuple > TypedSignal < ' c , C , Ps > {
79
+ impl < ' c , C : WithBaseField , Ps : meta :: ParamTuple > TypedSignal < ' c , C , Ps > {
58
80
#[ doc( hidden) ]
59
81
pub fn new ( owner : ObjectRef < ' c , C > , name : & ' static str ) -> Self {
60
82
Self {
@@ -68,11 +90,15 @@ impl<'c, C: WithBaseField, Ps: ParamTuple> TypedSignal<'c, C, Ps> {
68
90
self . owner . to_owned ( )
69
91
}
70
92
71
- pub fn emit ( & mut self , params : Ps ) {
93
+ /// Emit the signal with the given parameters.
94
+ ///
95
+ /// This is intended for generic use. Typically, you'll want to use the more specific `emit()` method of the code-generated signal
96
+ /// type, which also has named parameters.
97
+ pub fn emit_tuple ( & mut self , args : Ps ) {
72
98
let name = self . name . as_ref ( ) ;
73
99
74
100
self . owner . with_object_mut ( |obj| {
75
- obj. emit_signal ( name, & params . to_variant_array ( ) ) ;
101
+ obj. emit_signal ( name, & args . to_variant_array ( ) ) ;
76
102
} ) ;
77
103
}
78
104
@@ -85,10 +111,11 @@ impl<'c, C: WithBaseField, Ps: ParamTuple> TypedSignal<'c, C, Ps> {
85
111
/// sig.connect(|arg| { /* closure */ });
86
112
/// ```
87
113
///
88
- /// To connect to a method of the own object `self`, use [`connect_self()`][Self::connect_self].
114
+ /// To connect to a method of the own object `self`, use [`connect_self()`][Self::connect_self]. \
115
+ /// If you need cross-thread signals or connect flags, use [`connect_builder()`][Self::connect_builder].
89
116
pub fn connect < F > ( & mut self , mut function : F )
90
117
where
91
- F : AsFunc < ( ) , Ps > ,
118
+ F : SignalReceiver < ( ) , Ps > ,
92
119
{
93
120
let callable_name = std:: any:: type_name_of_val ( & function) ;
94
121
@@ -103,9 +130,12 @@ impl<'c, C: WithBaseField, Ps: ParamTuple> TypedSignal<'c, C, Ps> {
103
130
}
104
131
105
132
/// Connect a method (member function) with `&mut self` as the first parameter.
133
+ ///
134
+ /// To connect to methods on other objects, use [`connect_obj()`][Self::connect_obj]. \
135
+ /// If you need a `&self` receiver, cross-thread signals or connect flags, use [`connect_builder()`][Self::connect_builder].
106
136
pub fn connect_self < F > ( & mut self , mut function : F )
107
137
where
108
- for < ' c_rcv > F : AsFunc < & ' c_rcv mut C , Ps > ,
138
+ for < ' c_rcv > F : SignalReceiver < & ' c_rcv mut C , Ps > ,
109
139
{
110
140
// When using sys::short_type_name() in the future, make sure global "func" and member "MyClass::func" are rendered as such.
111
141
// PascalCase heuristic should then be good enough.
@@ -132,11 +162,12 @@ impl<'c, C: WithBaseField, Ps: ParamTuple> TypedSignal<'c, C, Ps> {
132
162
133
163
/// Connect a method (member function) with any `Gd<T>` (not `self`) as the first parameter.
134
164
///
135
- /// To connect to methods on the same object, use [`connect_self()`][Self::connect_self].
165
+ /// To connect to methods on the same object that declares the `#[signal]`, use [`connect_self()`][Self::connect_self]. \
166
+ /// If you need cross-thread signals or connect flags, use [`connect_builder()`][Self::connect_builder].
136
167
pub fn connect_obj < F , OtherC > ( & mut self , object : & Gd < OtherC > , mut function : F )
137
168
where
138
169
OtherC : GodotClass + Bounds < Declarer = bounds:: DeclUser > ,
139
- for < ' c_rcv > F : AsFunc < & ' c_rcv mut OtherC , Ps > ,
170
+ for < ' c_rcv > F : SignalReceiver < & ' c_rcv mut OtherC , Ps > ,
140
171
{
141
172
let callable_name = std:: any:: type_name_of_val ( & function) ;
142
173
@@ -154,6 +185,14 @@ impl<'c, C: WithBaseField, Ps: ParamTuple> TypedSignal<'c, C, Ps> {
154
185
self . inner_connect_local ( callable_name, godot_fn) ;
155
186
}
156
187
188
+ /// Fully customizable connection setup.
189
+ ///
190
+ /// The returned builder provides several methods to configure how to connect the signal. It needs to be finalized with a call to
191
+ /// [`ConnectBuilder::done()`].
192
+ pub fn connect_builder ( & mut self ) -> ConnectBuilder < ' _ , ' c , C , ( ) , Ps , ( ) > {
193
+ ConnectBuilder :: new ( self )
194
+ }
195
+
157
196
fn inner_connect_local < F > ( & mut self , callable_name : impl meta:: AsArg < GString > , godot_fn : F )
158
197
where
159
198
F : FnMut ( & [ & Variant ] ) -> Result < Variant , ( ) > + ' static ,
@@ -179,8 +218,4 @@ impl<'c, C: WithBaseField, Ps: ParamTuple> TypedSignal<'c, C, Ps> {
179
218
c. done ( ) ;
180
219
} ) ;
181
220
}
182
-
183
- pub fn connect_builder ( & mut self ) -> ConnectBuilder < ' _ , ' c , C , ( ) , Ps , ( ) > {
184
- ConnectBuilder :: new ( self )
185
- }
186
221
}
0 commit comments