6
6
*/
7
7
8
8
use godot:: builtin:: inner:: InnerCallable ;
9
- use godot:: builtin:: { varray, Callable , GString , StringName , Variant } ;
10
- use godot:: classes:: { Node2D , Object } ;
9
+ use godot:: builtin:: {
10
+ array, varray, Array , Callable , GString , NodePath , StringName , Variant , VariantArray ,
11
+ } ;
12
+ use godot:: classes:: { Node2D , Object , RefCounted } ;
11
13
use godot:: meta:: ToGodot ;
12
- use godot:: obj:: { NewAlloc , NewGd } ;
14
+ use godot:: obj:: { Gd , NewAlloc , NewGd } ;
13
15
use godot:: register:: { godot_api, GodotClass } ;
14
16
use std:: hash:: Hasher ;
15
17
use std:: sync:: atomic:: { AtomicU32 , Ordering } ;
@@ -33,6 +35,11 @@ impl CallableTestObj {
33
35
fn bar ( & self , b : i32 ) -> GString {
34
36
b. to_variant ( ) . stringify ( )
35
37
}
38
+
39
+ #[ func]
40
+ fn baz ( & self , a : i32 , b : GString , c : Array < NodePath > , d : Gd < RefCounted > ) -> VariantArray {
41
+ varray ! [ a, b, c, d]
42
+ }
36
43
}
37
44
38
45
#[ itest]
@@ -86,7 +93,7 @@ fn callable_object_method() {
86
93
}
87
94
88
95
#[ itest]
89
- fn callable_call ( ) {
96
+ fn callable_callv ( ) {
90
97
let obj = CallableTestObj :: new_gd ( ) ;
91
98
let callable = obj. callable ( "foo" ) ;
92
99
@@ -106,6 +113,30 @@ fn callable_call() {
106
113
assert_eq ! ( Callable :: invalid( ) . callv( & varray![ 1 , 2 , 3 ] ) , Variant :: nil( ) ) ;
107
114
}
108
115
116
+ #[ itest]
117
+ fn callable_call ( ) {
118
+ let obj = CallableTestObj :: new_gd ( ) ;
119
+ let callable = obj. callable ( "foo" ) ;
120
+
121
+ assert_eq ! ( obj. bind( ) . value, 0 ) ;
122
+ callable. call ( & [ 10 . to_variant ( ) ] ) ;
123
+ assert_eq ! ( obj. bind( ) . value, 10 ) ;
124
+
125
+ // Too many arguments: this call fails, its logic is not applied.
126
+ // In the future, panic should be propagated to caller.
127
+ callable. call ( & [ 20 . to_variant ( ) , 30 . to_variant ( ) ] ) ;
128
+ assert_eq ! ( obj. bind( ) . value, 10 ) ;
129
+
130
+ // TODO(bromeon): this causes a Rust panic, but since call() is routed to Godot, the panic is handled at the FFI boundary.
131
+ // Can there be a way to notify the caller about failed calls like that?
132
+ assert_eq ! ( callable. call( & [ "string" . to_variant( ) ] ) , Variant :: nil( ) ) ;
133
+
134
+ assert_eq ! (
135
+ Callable :: invalid( ) . call( & [ 1 . to_variant( ) , 2 . to_variant( ) , 3 . to_variant( ) ] ) ,
136
+ Variant :: nil( )
137
+ ) ;
138
+ }
139
+
109
140
#[ itest]
110
141
fn callable_call_return ( ) {
111
142
let obj = CallableTestObj :: new_gd ( ) ;
@@ -151,24 +182,90 @@ fn callable_bindv() {
151
182
) ;
152
183
}
153
184
154
- // This is also testing that using works at all.
155
185
#[ itest]
156
- #[ cfg( since_api = "4.2" ) ]
157
- fn callable_varargs ( ) {
158
- // TODO: Replace with proper apis instead of using `InnerCallable`.
159
- use godot:: builtin:: inner;
186
+ fn callable_bind ( ) {
160
187
let obj = CallableTestObj :: new_gd ( ) ;
161
188
let callable = obj. callable ( "bar" ) ;
162
- let inner_callable = inner:: InnerCallable :: from_outer ( & callable) ;
163
- let callable_bound = inner_callable. bind ( & [ 10 . to_variant ( ) ] ) ;
164
- let inner_callable_bound = inner:: InnerCallable :: from_outer ( & callable_bound) ;
189
+ let callable_bound = callable. bind ( & [ 10 . to_variant ( ) ] ) ;
165
190
166
191
assert_eq ! (
167
- inner_callable_bound . call( & [ ] ) ,
192
+ callable_bound . call( & [ ] ) ,
168
193
10 . to_variant( ) . stringify( ) . to_variant( )
169
194
) ;
170
195
}
171
196
197
+ #[ itest]
198
+ fn callable_unbind ( ) {
199
+ let obj = CallableTestObj :: new_gd ( ) ;
200
+ let callable = obj. callable ( "bar" ) ;
201
+ let callable_unbound = callable. unbind ( 3 ) ;
202
+
203
+ assert_eq ! (
204
+ callable_unbound. call( & [
205
+ 121 . to_variant( ) ,
206
+ 20 . to_variant( ) ,
207
+ 30 . to_variant( ) ,
208
+ 40 . to_variant( )
209
+ ] ) ,
210
+ 121 . to_variant( ) . stringify( ) . to_variant( )
211
+ ) ;
212
+ }
213
+
214
+ #[ itest]
215
+ fn callable_arg_len ( ) {
216
+ let obj = CallableTestObj :: new_gd ( ) ;
217
+
218
+ assert_eq ! ( obj. callable( "foo" ) . arg_len( ) , 1 ) ;
219
+ assert_eq ! ( obj. callable( "bar" ) . arg_len( ) , 1 ) ;
220
+ assert_eq ! ( obj. callable( "baz" ) . arg_len( ) , 4 ) ;
221
+ assert_eq ! ( obj. callable( "foo" ) . unbind( 10 ) . arg_len( ) , 11 ) ;
222
+ assert_eq ! (
223
+ obj. callable( "baz" )
224
+ . bind( & [ 10 . to_variant( ) , "hello" . to_variant( ) ] )
225
+ . arg_len( ) ,
226
+ 2
227
+ ) ;
228
+ }
229
+
230
+ #[ itest]
231
+ fn callable_bound_args_len ( ) {
232
+ let obj = CallableTestObj :: new_gd ( ) ;
233
+
234
+ assert_eq ! ( obj. callable( "foo" ) . bound_args_len( ) , 0 ) ;
235
+ assert_eq ! (
236
+ obj. callable( "foo" )
237
+ . bind( & [ 10 . to_variant( ) ] )
238
+ . bound_args_len( ) ,
239
+ 1
240
+ ) ;
241
+ assert_eq ! ( obj. callable( "foo" ) . unbind( 28 ) . bound_args_len( ) , -28 ) ;
242
+ assert_eq ! (
243
+ obj. callable( "foo" )
244
+ . bind( & [ 10 . to_variant( ) ] )
245
+ . unbind( 5 )
246
+ . bound_args_len( ) ,
247
+ -4
248
+ ) ;
249
+ }
250
+
251
+ #[ itest]
252
+ fn callable_get_bound_arguments ( ) {
253
+ let obj = CallableTestObj :: new_gd ( ) ;
254
+
255
+ let a = 10 . to_variant ( ) ;
256
+ let b = "hello!" . to_variant ( ) ;
257
+ let c: Array < NodePath > = array ! [ "my/node/path" ] ;
258
+ let c = c. to_variant ( ) ;
259
+ let d = RefCounted :: new_gd ( ) . to_variant ( ) ;
260
+
261
+ let callable = obj. callable ( "baz" ) ;
262
+ let callable_bound = callable. bind ( & [ a. clone ( ) , b. clone ( ) , c. clone ( ) , d. clone ( ) ] ) ;
263
+
264
+ assert_eq ! ( callable_bound. get_bound_arguments( ) , varray![ a, b, c, d] ) ;
265
+ }
266
+
267
+ // TODO: Add tests for `Callable::rpc` and `Callable::rpc_id`.
268
+
172
269
// Testing https://github.com/godot-rust/gdext/issues/410
173
270
174
271
#[ derive( GodotClass ) ]
0 commit comments