5
5
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
6
*/
7
7
8
- use godot :: builtin :: inner :: InnerCallable ;
8
+ use crate :: framework :: itest ;
9
9
use godot:: builtin:: {
10
- array, varray, Array , Callable , GString , NodePath , StringName , Variant , VariantArray ,
10
+ array, varray, Array , Callable , GString , NodePath , StringName , Variant , VariantArray , Vector2 ,
11
11
} ;
12
12
use godot:: classes:: { Node2D , Object , RefCounted } ;
13
+ use godot:: init:: GdextBuild ;
13
14
use godot:: meta:: ToGodot ;
14
15
use godot:: obj:: { Gd , NewAlloc , NewGd } ;
15
16
use godot:: register:: { godot_api, GodotClass } ;
16
17
use std:: hash:: Hasher ;
17
18
use std:: sync:: atomic:: { AtomicU32 , Ordering } ;
18
19
19
- use crate :: framework:: itest;
20
-
21
20
#[ derive( GodotClass ) ]
22
21
#[ class( init, base=RefCounted ) ]
23
22
struct CallableTestObj {
@@ -27,43 +26,38 @@ struct CallableTestObj {
27
26
#[ godot_api]
28
27
impl CallableTestObj {
29
28
#[ func]
30
- fn foo ( & mut self , a : i32 ) {
31
- self . value = a ;
29
+ fn stringify_int ( & self , int : i32 ) -> GString {
30
+ int . to_variant ( ) . stringify ( )
32
31
}
33
32
34
33
#[ func]
35
- fn bar ( & self , b : i32 ) -> GString {
36
- b . to_variant ( ) . stringify ( )
34
+ fn assign_int ( & mut self , int : i32 ) {
35
+ self . value = int ;
37
36
}
38
37
39
- #[ func]
40
- fn baz ( & self , a : i32 , b : GString , c : Array < NodePath > , d : Gd < RefCounted > ) -> VariantArray {
38
+ #[ func] // static
39
+ fn concat_array ( a : i32 , b : GString , c : Array < NodePath > , d : Gd < RefCounted > ) -> VariantArray {
41
40
varray ! [ a, b, c, d]
42
41
}
43
-
44
- #[ func]
45
- fn static_function ( c : i32 ) -> GString {
46
- c. to_variant ( ) . stringify ( )
47
- }
48
42
}
49
43
50
44
#[ itest]
51
45
fn callable_validity ( ) {
52
46
let obj = CallableTestObj :: new_gd ( ) ;
53
47
54
- // non -null object, valid method
55
- assert ! ( obj. callable( "foo " ) . is_valid( ) ) ;
56
- assert ! ( !obj. callable( "foo " ) . is_null( ) ) ;
57
- assert ! ( !obj. callable( "foo " ) . is_custom( ) ) ;
58
- assert ! ( obj. callable( "foo " ) . object( ) . is_some( ) ) ;
48
+ // Non -null object, valid method.
49
+ assert ! ( obj. callable( "assign_int " ) . is_valid( ) ) ;
50
+ assert ! ( !obj. callable( "assign_int " ) . is_null( ) ) ;
51
+ assert ! ( !obj. callable( "assign_int " ) . is_custom( ) ) ;
52
+ assert ! ( obj. callable( "assign_int " ) . object( ) . is_some( ) ) ;
59
53
60
- // non -null object, invalid method
61
- assert ! ( !obj. callable( "doesn't_exist " ) . is_valid( ) ) ;
62
- assert ! ( !obj. callable( "doesn't_exist " ) . is_null( ) ) ;
63
- assert ! ( !obj. callable( "doesn't_exist " ) . is_custom( ) ) ;
64
- assert ! ( obj. callable( "doesn't_exist " ) . object( ) . is_some( ) ) ;
54
+ // Non -null object, invalid method.
55
+ assert ! ( !obj. callable( "doesnt_exist " ) . is_valid( ) ) ;
56
+ assert ! ( !obj. callable( "doesnt_exist " ) . is_null( ) ) ;
57
+ assert ! ( !obj. callable( "doesnt_exist " ) . is_custom( ) ) ;
58
+ assert ! ( obj. callable( "doesnt_exist " ) . object( ) . is_some( ) ) ;
65
59
66
- // null object
60
+ // Null object.
67
61
assert ! ( !Callable :: invalid( ) . is_valid( ) ) ;
68
62
assert ! ( Callable :: invalid( ) . is_null( ) ) ;
69
63
assert ! ( !Callable :: invalid( ) . is_custom( ) ) ;
@@ -75,19 +69,27 @@ fn callable_validity() {
75
69
#[ itest]
76
70
fn callable_hash ( ) {
77
71
let obj = CallableTestObj :: new_gd ( ) ;
78
- assert_eq ! ( obj. callable( "foo" ) . hash( ) , obj. callable( "foo" ) . hash( ) ) ;
79
- assert_ne ! ( obj. callable( "foo" ) . hash( ) , obj. callable( "bar" ) . hash( ) ) ;
72
+ assert_eq ! (
73
+ obj. callable( "assign_int" ) . hash( ) ,
74
+ obj. callable( "assign_int" ) . hash( )
75
+ ) ;
76
+
77
+ // Not guaranteed, but unlikely.
78
+ assert_ne ! (
79
+ obj. callable( "assign_int" ) . hash( ) ,
80
+ obj. callable( "stringify_int" ) . hash( )
81
+ ) ;
80
82
}
81
83
82
84
#[ itest]
83
85
fn callable_object_method ( ) {
84
86
let object = CallableTestObj :: new_gd ( ) ;
85
87
let object_id = object. instance_id ( ) ;
86
- let callable = object. callable ( "foo " ) ;
88
+ let callable = object. callable ( "assign_int " ) ;
87
89
88
90
assert_eq ! ( callable. object( ) , Some ( object. clone( ) . upcast:: <Object >( ) ) ) ;
89
91
assert_eq ! ( callable. object_id( ) , Some ( object_id) ) ;
90
- assert_eq ! ( callable. method_name( ) , Some ( "foo " . into( ) ) ) ;
92
+ assert_eq ! ( callable. method_name( ) , Some ( "assign_int " . into( ) ) ) ;
91
93
92
94
// Invalidating the object still returns the old ID, however not the object.
93
95
drop ( object) ;
@@ -97,7 +99,7 @@ fn callable_object_method() {
97
99
98
100
#[ itest]
99
101
fn callable_static ( ) {
100
- let callable = Callable :: from_local_static ( "CallableTestObj" , "static_function " ) ;
102
+ let callable = Callable :: from_local_static ( "CallableTestObj" , "concat_array " ) ;
101
103
102
104
// Test current behavior in <4.4 and >=4.4. Although our API explicitly leaves it unspecified, we then notice change in implementation.
103
105
if cfg ! ( since_api = "4.4" ) {
@@ -107,13 +109,21 @@ fn callable_static() {
107
109
} else {
108
110
assert ! ( callable. object( ) . is_some( ) ) ;
109
111
assert ! ( callable. object_id( ) . is_some( ) ) ;
110
- assert_eq ! ( callable. method_name( ) , Some ( "static_function " . into( ) ) ) ;
111
- assert_eq ! ( callable. to_string( ) , "GDScriptNativeClass::static_function " ) ;
112
+ assert_eq ! ( callable. method_name( ) , Some ( "concat_array " . into( ) ) ) ;
113
+ assert_eq ! ( callable. to_string( ) , "GDScriptNativeClass::concat_array " ) ;
112
114
}
113
115
114
116
// Calling works consistently everywhere.
115
- let result = callable. callv ( & varray ! [ 12345 ] ) ;
116
- assert_eq ! ( result, "12345" . to_variant( ) ) ;
117
+ let result = callable. callv ( & varray ! [
118
+ 10 ,
119
+ "hello" ,
120
+ & array![ & NodePath :: from( "my/node/path" ) ] ,
121
+ RefCounted :: new_gd( )
122
+ ] ) ;
123
+
124
+ let result = result. to :: < VariantArray > ( ) ;
125
+ assert_eq ! ( result. len( ) , 4 ) ;
126
+ assert_eq ! ( result. at( 0 ) , 10 . to_variant( ) ) ;
117
127
118
128
#[ cfg( since_api = "4.3" ) ]
119
129
assert_eq ! ( callable. get_argument_count( ) , 0 ) ; // Consistently doesn't work :)
@@ -122,7 +132,7 @@ fn callable_static() {
122
132
#[ itest]
123
133
fn callable_callv ( ) {
124
134
let obj = CallableTestObj :: new_gd ( ) ;
125
- let callable = obj. callable ( "foo " ) ;
135
+ let callable = obj. callable ( "assign_int " ) ;
126
136
127
137
assert_eq ! ( obj. bind( ) . value, 0 ) ;
128
138
callable. callv ( & varray ! [ 10 ] ) ;
@@ -143,20 +153,18 @@ fn callable_callv() {
143
153
#[ cfg( since_api = "4.2" ) ]
144
154
#[ itest]
145
155
fn callable_call ( ) {
156
+ // See callable_callv() for future improvements.
157
+
146
158
let obj = CallableTestObj :: new_gd ( ) ;
147
- let callable = obj. callable ( "foo " ) ;
159
+ let callable = obj. callable ( "assign_int " ) ;
148
160
149
161
assert_eq ! ( obj. bind( ) . value, 0 ) ;
150
162
callable. call ( & [ 10 . to_variant ( ) ] ) ;
151
163
assert_eq ! ( obj. bind( ) . value, 10 ) ;
152
164
153
- // Too many arguments: this call fails, its logic is not applied.
154
- // In the future, panic should be propagated to caller.
155
165
callable. call ( & [ 20 . to_variant ( ) , 30 . to_variant ( ) ] ) ;
156
166
assert_eq ! ( obj. bind( ) . value, 10 ) ;
157
167
158
- // TODO(bromeon): this causes a Rust panic, but since call() is routed to Godot, the panic is handled at the FFI boundary.
159
- // Can there be a way to notify the caller about failed calls like that?
160
168
assert_eq ! ( callable. call( & [ "string" . to_variant( ) ] ) , Variant :: nil( ) ) ;
161
169
162
170
assert_eq ! (
@@ -168,40 +176,43 @@ fn callable_call() {
168
176
#[ itest]
169
177
fn callable_call_return ( ) {
170
178
let obj = CallableTestObj :: new_gd ( ) ;
171
- let callable = obj. callable ( "bar " ) ;
179
+ let callable = obj. callable ( "stringify_int " ) ;
172
180
173
181
assert_eq ! (
174
182
callable. callv( & varray![ 10 ] ) ,
175
183
10 . to_variant( ) . stringify( ) . to_variant( )
176
184
) ;
177
- // Errors in Godot, but should not crash.
185
+
186
+ // Causes error in Godot, but should not crash.
178
187
assert_eq ! ( callable. callv( & varray![ "string" ] ) , Variant :: nil( ) ) ;
179
188
}
180
189
190
+ #[ cfg( since_api = "4.2" ) ]
181
191
#[ itest]
182
192
fn callable_call_engine ( ) {
183
193
let obj = Node2D :: new_alloc ( ) ;
184
194
let cb = Callable :: from_object_method ( & obj, "set_position" ) ;
185
- let inner: InnerCallable = cb. as_inner ( ) ;
186
195
187
- assert ! ( !inner . is_null( ) ) ;
188
- assert_eq ! ( inner . get_object_id ( ) , obj. instance_id( ) . to_i64 ( ) ) ;
189
- assert_eq ! ( inner . get_method ( ) , StringName :: from( "set_position" ) ) ;
196
+ assert ! ( !cb . is_null( ) ) ;
197
+ assert_eq ! ( cb . object_id ( ) , Some ( obj. instance_id( ) ) ) ;
198
+ assert_eq ! ( cb . method_name ( ) , Some ( StringName :: from( "set_position" ) ) ) ;
190
199
191
- // TODO once varargs is available
192
- // let pos = Vector2::new(5.0, 7.0);
193
- // inner.call(&[pos.to_variant()]);
194
- // assert_eq!(obj.get_position(), pos);
195
- //
196
- // inner.bindv(array);
200
+ let pos = Vector2 :: new ( 5.0 , 7.0 ) ;
201
+ cb. call ( & [ pos. to_variant ( ) ] ) ;
202
+ assert_eq ! ( obj. get_position( ) , pos) ;
203
+
204
+ let pos = Vector2 :: new ( 1.0 , 23.0 ) ;
205
+ let bound = cb. bind ( & [ pos. to_variant ( ) ] ) ;
206
+ bound. call ( & [ ] ) ;
207
+ assert_eq ! ( obj. get_position( ) , pos) ;
197
208
198
209
obj. free ( ) ;
199
210
}
200
211
201
212
#[ itest]
202
213
fn callable_bindv ( ) {
203
214
let obj = CallableTestObj :: new_gd ( ) ;
204
- let callable = obj. callable ( "bar " ) ;
215
+ let callable = obj. callable ( "stringify_int " ) ;
205
216
let callable_bound = callable. bindv ( & varray ! [ 10 ] ) ;
206
217
207
218
assert_eq ! (
@@ -214,7 +225,7 @@ fn callable_bindv() {
214
225
#[ itest]
215
226
fn callable_bind ( ) {
216
227
let obj = CallableTestObj :: new_gd ( ) ;
217
- let callable = obj. callable ( "bar " ) ;
228
+ let callable = obj. callable ( "stringify_int " ) ;
218
229
let callable_bound = callable. bind ( & [ 10 . to_variant ( ) ] ) ;
219
230
220
231
assert_eq ! (
@@ -227,7 +238,7 @@ fn callable_bind() {
227
238
#[ itest]
228
239
fn callable_unbind ( ) {
229
240
let obj = CallableTestObj :: new_gd ( ) ;
230
- let callable = obj. callable ( "bar " ) ;
241
+ let callable = obj. callable ( "stringify_int " ) ;
231
242
let callable_unbound = callable. unbind ( 3 ) ;
232
243
233
244
assert_eq ! (
@@ -243,34 +254,39 @@ fn callable_unbind() {
243
254
244
255
#[ cfg( since_api = "4.3" ) ]
245
256
#[ itest]
246
- fn callable_arg_len ( ) {
257
+ fn callable_get_argument_count ( ) {
247
258
let obj = CallableTestObj :: new_gd ( ) ;
248
259
249
- assert_eq ! ( obj. callable( "foo" ) . get_argument_count( ) , 1 ) ;
250
- assert_eq ! ( obj. callable( "bar" ) . get_argument_count( ) , 1 ) ;
251
- assert_eq ! ( obj. callable( "baz" ) . get_argument_count( ) , 4 ) ;
252
- assert_eq ! ( obj. callable( "foo" ) . unbind( 10 ) . get_argument_count( ) , 11 ) ;
260
+ let assign_int = obj. callable ( "assign_int" ) ;
261
+ assert_eq ! ( assign_int. get_argument_count( ) , 1 ) ;
262
+ assert_eq ! ( assign_int. unbind( 10 ) . get_argument_count( ) , 11 ) ;
263
+
264
+ assert_eq ! ( obj. callable( "stringify_int" ) . get_argument_count( ) , 1 ) ;
265
+
266
+ let concat_array = obj. callable ( "concat_array" ) ;
267
+ assert_eq ! ( concat_array. get_argument_count( ) , 4 ) ;
253
268
assert_eq ! (
254
- obj . callable ( "baz" )
269
+ concat_array
255
270
. bind( & [ 10 . to_variant( ) , "hello" . to_variant( ) ] )
256
271
. get_argument_count( ) ,
257
272
2
258
273
) ;
259
274
}
260
275
261
276
#[ itest]
262
- fn callable_bound_args_len ( ) {
263
- // Note: bug regarding get_bound_arguments_count() returning negative numbers has been fixed in godot-rust also for older versions.
264
-
277
+ fn callable_get_bound_arguments_count ( ) {
265
278
let obj = CallableTestObj :: new_gd ( ) ;
266
- let original = obj. callable ( "foo " ) ;
279
+ let original = obj. callable ( "assign_int " ) ;
267
280
268
281
assert_eq ! ( original. get_bound_arguments_count( ) , 0 ) ;
269
282
assert_eq ! ( original. unbind( 28 ) . get_bound_arguments_count( ) , 0 ) ;
270
283
271
284
let with_1_arg = original. bindv ( & varray ! [ 10 ] ) ;
272
285
assert_eq ! ( with_1_arg. get_bound_arguments_count( ) , 1 ) ;
273
- assert_eq ! ( with_1_arg. unbind( 5 ) . get_bound_arguments_count( ) , 1 ) ;
286
+
287
+ // Note: bug regarding get_bound_arguments_count() before 4.4; godot-rust caps at 0.
288
+ let expected = if GdextBuild :: since_api ( "4.4" ) { 1 } else { 0 } ;
289
+ assert_eq ! ( with_1_arg. unbind( 5 ) . get_bound_arguments_count( ) , expected) ;
274
290
}
275
291
276
292
#[ itest]
@@ -288,10 +304,7 @@ fn callable_get_bound_arguments() {
288
304
assert_eq ! ( callable_bound. get_bound_arguments( ) , varray![ a, b, c, d] ) ;
289
305
}
290
306
291
- // TODO: Add tests for `Callable::rpc` and `Callable::rpc_id`.
292
-
293
- // Testing https://github.com/godot-rust/gdext/issues/410
294
-
307
+ // Regression test for https://github.com/godot-rust/gdext/issues/410.
295
308
#[ derive( GodotClass ) ]
296
309
#[ class( init, base = Node ) ]
297
310
pub struct CallableRefcountTest { }
@@ -407,7 +420,8 @@ pub mod custom_callable {
407
420
fn callable_custom_with_err ( ) {
408
421
let callable_with_err =
409
422
Callable :: from_local_fn ( "on_error_doesnt_crash" , |_args : & [ & Variant ] | Err ( ( ) ) ) ;
410
- // Errors in Godot, but should not crash.
423
+
424
+ // Causes error in Godot, but should not crash.
411
425
assert_eq ! ( callable_with_err. callv( & varray![ ] ) , Variant :: nil( ) ) ;
412
426
}
413
427
@@ -538,6 +552,9 @@ pub mod custom_callable {
538
552
assert_eq ! ( 1 , received. load( Ordering :: SeqCst ) ) ;
539
553
}
540
554
555
+ // ------------------------------------------------------------------------------------------------------------------------------------------
556
+ // Helper structs and functions for custom callables
557
+
541
558
struct Adder {
542
559
sum : i32 ,
543
560
@@ -644,5 +661,3 @@ pub mod custom_callable {
644
661
}
645
662
}
646
663
}
647
-
648
- // ----------------------------------------------------------------------------------------------------------------------------------------------
0 commit comments