Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/variant/callable.cpp
9903 views
1
/**************************************************************************/
2
/* callable.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "callable.h"
32
33
#include "core/object/object.h"
34
#include "core/object/ref_counted.h"
35
#include "core/object/script_language.h"
36
#include "core/variant/callable_bind.h"
37
#include "core/variant/variant_callable.h"
38
39
void Callable::call_deferredp(const Variant **p_arguments, int p_argcount) const {
40
MessageQueue::get_singleton()->push_callablep(*this, p_arguments, p_argcount, true);
41
}
42
43
void Callable::callp(const Variant **p_arguments, int p_argcount, Variant &r_return_value, CallError &r_call_error) const {
44
if (is_null()) {
45
r_call_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL;
46
r_call_error.argument = 0;
47
r_call_error.expected = 0;
48
r_return_value = Variant();
49
} else if (is_custom()) {
50
if (!is_valid()) {
51
r_call_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL;
52
r_call_error.argument = 0;
53
r_call_error.expected = 0;
54
r_return_value = Variant();
55
return;
56
}
57
custom->call(p_arguments, p_argcount, r_return_value, r_call_error);
58
} else {
59
Object *obj = ObjectDB::get_instance(ObjectID(object));
60
#ifdef DEBUG_ENABLED
61
if (!obj) {
62
r_call_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL;
63
r_call_error.argument = 0;
64
r_call_error.expected = 0;
65
r_return_value = Variant();
66
return;
67
}
68
#endif
69
r_return_value = obj->callp(method, p_arguments, p_argcount, r_call_error);
70
}
71
}
72
73
Variant Callable::callv(const Array &p_arguments) const {
74
int argcount = p_arguments.size();
75
const Variant **argptrs = nullptr;
76
if (argcount) {
77
argptrs = (const Variant **)alloca(sizeof(Variant *) * argcount);
78
for (int i = 0; i < argcount; i++) {
79
argptrs[i] = &p_arguments[i];
80
}
81
}
82
CallError ce;
83
Variant ret;
84
callp(argptrs, argcount, ret, ce);
85
return ret;
86
}
87
88
Error Callable::rpcp(int p_id, const Variant **p_arguments, int p_argcount, CallError &r_call_error) const {
89
if (is_null()) {
90
r_call_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL;
91
r_call_error.argument = 0;
92
r_call_error.expected = 0;
93
return ERR_UNCONFIGURED;
94
} else if (!is_custom()) {
95
Object *obj = ObjectDB::get_instance(ObjectID(object));
96
#ifdef DEBUG_ENABLED
97
if (!obj || !obj->is_class("Node")) {
98
r_call_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL;
99
r_call_error.argument = 0;
100
r_call_error.expected = 0;
101
return ERR_UNCONFIGURED;
102
}
103
#endif
104
105
int argcount = p_argcount + 2;
106
const Variant **argptrs = (const Variant **)alloca(sizeof(Variant *) * argcount);
107
const Variant args[2] = { p_id, method };
108
109
argptrs[0] = &args[0];
110
argptrs[1] = &args[1];
111
for (int i = 0; i < p_argcount; ++i) {
112
argptrs[i + 2] = p_arguments[i];
113
}
114
115
CallError tmp; // TODO: Check `tmp`?
116
Error err = (Error)obj->callp(SNAME("rpc_id"), argptrs, argcount, tmp).operator int64_t();
117
118
r_call_error.error = Callable::CallError::CALL_OK;
119
return err;
120
} else {
121
return custom->rpc(p_id, p_arguments, p_argcount, r_call_error);
122
}
123
}
124
125
Callable Callable::bindp(const Variant **p_arguments, int p_argcount) const {
126
Vector<Variant> args;
127
args.resize(p_argcount);
128
for (int i = 0; i < p_argcount; i++) {
129
args.write[i] = *p_arguments[i];
130
}
131
return Callable(memnew(CallableCustomBind(*this, args)));
132
}
133
134
Callable Callable::bindv(const Array &p_arguments) {
135
if (p_arguments.is_empty()) {
136
return *this; // No point in creating a new callable if nothing is bound.
137
}
138
139
Vector<Variant> args;
140
args.resize(p_arguments.size());
141
for (int i = 0; i < p_arguments.size(); i++) {
142
args.write[i] = p_arguments[i];
143
}
144
return Callable(memnew(CallableCustomBind(*this, args)));
145
}
146
147
Callable Callable::unbind(int p_argcount) const {
148
ERR_FAIL_COND_V_MSG(p_argcount <= 0, Callable(*this), "Amount of unbind() arguments must be 1 or greater.");
149
return Callable(memnew(CallableCustomUnbind(*this, p_argcount)));
150
}
151
152
bool Callable::is_valid() const {
153
if (is_custom()) {
154
return get_custom()->is_valid();
155
} else {
156
return get_object() && get_object()->has_method(get_method());
157
}
158
}
159
160
Object *Callable::get_object() const {
161
if (is_null()) {
162
return nullptr;
163
} else if (is_custom()) {
164
return ObjectDB::get_instance(custom->get_object());
165
} else {
166
return ObjectDB::get_instance(ObjectID(object));
167
}
168
}
169
170
ObjectID Callable::get_object_id() const {
171
if (is_null()) {
172
return ObjectID();
173
} else if (is_custom()) {
174
return custom->get_object();
175
} else {
176
return ObjectID(object);
177
}
178
}
179
180
StringName Callable::get_method() const {
181
if (is_custom()) {
182
return get_custom()->get_method();
183
}
184
return method;
185
}
186
187
int Callable::get_argument_count(bool *r_is_valid) const {
188
if (is_custom()) {
189
bool valid = false;
190
return custom->get_argument_count(r_is_valid ? *r_is_valid : valid);
191
} else if (is_valid()) {
192
return get_object()->get_method_argument_count(method, r_is_valid);
193
} else {
194
if (r_is_valid) {
195
*r_is_valid = false;
196
}
197
return 0;
198
}
199
}
200
201
int Callable::get_bound_arguments_count() const {
202
if (!is_null() && is_custom()) {
203
return custom->get_bound_arguments_count();
204
} else {
205
return 0;
206
}
207
}
208
209
void Callable::get_bound_arguments_ref(Vector<Variant> &r_arguments) const {
210
if (!is_null() && is_custom()) {
211
custom->get_bound_arguments(r_arguments);
212
} else {
213
r_arguments.clear();
214
}
215
}
216
217
Array Callable::get_bound_arguments() const {
218
Vector<Variant> arr;
219
get_bound_arguments_ref(arr);
220
Array ret;
221
ret.resize(arr.size());
222
for (int i = 0; i < arr.size(); i++) {
223
ret[i] = arr[i];
224
}
225
return ret;
226
}
227
228
int Callable::get_unbound_arguments_count() const {
229
if (!is_null() && is_custom()) {
230
return custom->get_unbound_arguments_count();
231
} else {
232
return 0;
233
}
234
}
235
236
CallableCustom *Callable::get_custom() const {
237
ERR_FAIL_COND_V_MSG(!is_custom(), nullptr,
238
vformat("Can't get custom on non-CallableCustom \"%s\".", operator String()));
239
return custom;
240
}
241
242
const Callable *Callable::get_base_comparator() const {
243
const Callable *comparator = nullptr;
244
if (is_custom()) {
245
comparator = custom->get_base_comparator();
246
}
247
if (comparator) {
248
return comparator;
249
} else {
250
return this;
251
}
252
}
253
254
uint32_t Callable::hash() const {
255
if (is_custom()) {
256
return custom->hash();
257
} else {
258
uint32_t hash = method.hash();
259
hash = hash_murmur3_one_64(object, hash);
260
return hash_fmix32(hash);
261
}
262
}
263
264
bool Callable::operator==(const Callable &p_callable) const {
265
bool custom_a = is_custom();
266
bool custom_b = p_callable.is_custom();
267
268
if (custom_a == custom_b) {
269
if (custom_a) {
270
if (custom == p_callable.custom) {
271
return true; //same pointer, don't even compare
272
}
273
274
CallableCustom::CompareEqualFunc eq_a = custom->get_compare_equal_func();
275
CallableCustom::CompareEqualFunc eq_b = p_callable.custom->get_compare_equal_func();
276
if (eq_a == eq_b) {
277
return eq_a(custom, p_callable.custom);
278
} else {
279
return false;
280
}
281
} else {
282
return object == p_callable.object && method == p_callable.method;
283
}
284
} else {
285
return false;
286
}
287
}
288
289
bool Callable::operator!=(const Callable &p_callable) const {
290
return !(*this == p_callable);
291
}
292
293
bool Callable::operator<(const Callable &p_callable) const {
294
bool custom_a = is_custom();
295
bool custom_b = p_callable.is_custom();
296
297
if (custom_a == custom_b) {
298
if (custom_a) {
299
if (custom == p_callable.custom) {
300
return false; //same pointer, don't even compare
301
}
302
303
CallableCustom::CompareLessFunc less_a = custom->get_compare_less_func();
304
CallableCustom::CompareLessFunc less_b = p_callable.custom->get_compare_less_func();
305
if (less_a == less_b) {
306
return less_a(custom, p_callable.custom);
307
} else {
308
return less_a < less_b; //it's something..
309
}
310
311
} else {
312
if (object == p_callable.object) {
313
return method < p_callable.method;
314
} else {
315
return object < p_callable.object;
316
}
317
}
318
} else {
319
return int(custom_a ? 1 : 0) < int(custom_b ? 1 : 0);
320
}
321
}
322
323
void Callable::operator=(const Callable &p_callable) {
324
CallableCustom *cleanup_ref = nullptr;
325
if (is_custom()) {
326
if (p_callable.is_custom()) {
327
if (custom == p_callable.custom) {
328
return;
329
}
330
}
331
cleanup_ref = custom;
332
custom = nullptr;
333
}
334
335
if (p_callable.is_custom()) {
336
method = StringName();
337
object = 0;
338
if (p_callable.custom->ref_count.ref()) {
339
custom = p_callable.custom;
340
}
341
} else {
342
method = p_callable.method;
343
object = p_callable.object;
344
}
345
346
if (cleanup_ref != nullptr && cleanup_ref->ref_count.unref()) {
347
memdelete(cleanup_ref);
348
}
349
cleanup_ref = nullptr;
350
}
351
352
Callable::operator String() const {
353
if (is_custom()) {
354
return custom->get_as_text();
355
} else {
356
if (is_null()) {
357
return "null::null";
358
}
359
360
Object *base = get_object();
361
if (base) {
362
String class_name = base->get_class();
363
Ref<Script> script = base->get_script();
364
if (script.is_valid()) {
365
if (!script->get_global_name().is_empty()) {
366
class_name += "(" + script->get_global_name() + ")";
367
} else if (script->get_path().is_resource_file()) {
368
class_name += "(" + script->get_path().get_file() + ")";
369
}
370
}
371
return class_name + "::" + String(method);
372
} else {
373
return "null::" + String(method);
374
}
375
}
376
}
377
378
Callable Callable::create(const Variant &p_variant, const StringName &p_method) {
379
ERR_FAIL_COND_V_MSG(p_method == StringName(), Callable(), "Method argument to Callable::create method must be a non-empty string.");
380
381
switch (p_variant.get_type()) {
382
case Variant::NIL:
383
return Callable(ObjectID(), p_method);
384
case Variant::OBJECT:
385
return Callable(p_variant.operator ObjectID(), p_method);
386
default:
387
return Callable(memnew(VariantCallable(p_variant, p_method)));
388
}
389
}
390
391
Callable::Callable(const Object *p_object, const StringName &p_method) {
392
if (unlikely(p_method == StringName())) {
393
object = 0;
394
ERR_FAIL_MSG("Method argument to Callable constructor must be a non-empty string.");
395
}
396
if (unlikely(p_object == nullptr)) {
397
object = 0;
398
ERR_FAIL_MSG("Object argument to Callable constructor must be non-null.");
399
}
400
401
object = p_object->get_instance_id();
402
method = p_method;
403
}
404
405
Callable::Callable(ObjectID p_object, const StringName &p_method) {
406
if (unlikely(p_method == StringName())) {
407
object = 0;
408
ERR_FAIL_MSG("Method argument to Callable constructor must be a non-empty string.");
409
}
410
411
object = p_object;
412
method = p_method;
413
}
414
415
Callable::Callable(CallableCustom *p_custom) {
416
if (unlikely(p_custom->referenced)) {
417
object = 0;
418
ERR_FAIL_MSG("Callable custom is already referenced.");
419
}
420
p_custom->referenced = true;
421
object = 0; //ensure object is all zero, since pointer may be 32 bits
422
custom = p_custom;
423
}
424
425
Callable::Callable(const Callable &p_callable) {
426
if (p_callable.is_custom()) {
427
if (!p_callable.custom->ref_count.ref()) {
428
object = 0;
429
} else {
430
object = 0;
431
custom = p_callable.custom;
432
}
433
} else {
434
method = p_callable.method;
435
object = p_callable.object;
436
}
437
}
438
439
Callable::~Callable() {
440
if (is_custom()) {
441
if (custom->ref_count.unref()) {
442
memdelete(custom);
443
custom = nullptr;
444
}
445
}
446
}
447
448
bool CallableCustom::is_valid() const {
449
// Sensible default implementation so most custom callables don't need their own.
450
return ObjectDB::get_instance(get_object());
451
}
452
453
StringName CallableCustom::get_method() const {
454
ERR_FAIL_V_MSG(StringName(), vformat("Can't get method on CallableCustom \"%s\".", get_as_text()));
455
}
456
457
Error CallableCustom::rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const {
458
r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
459
r_call_error.argument = 0;
460
r_call_error.expected = 0;
461
return ERR_UNCONFIGURED;
462
}
463
464
const Callable *CallableCustom::get_base_comparator() const {
465
return nullptr;
466
}
467
468
int CallableCustom::get_argument_count(bool &r_is_valid) const {
469
r_is_valid = false;
470
return 0;
471
}
472
473
int CallableCustom::get_bound_arguments_count() const {
474
return 0;
475
}
476
477
void CallableCustom::get_bound_arguments(Vector<Variant> &r_arguments) const {
478
r_arguments.clear();
479
}
480
481
int CallableCustom::get_unbound_arguments_count() const {
482
return 0;
483
}
484
485
CallableCustom::CallableCustom() {
486
ref_count.init();
487
}
488
489
//////////////////////////////////
490
491
Object *Signal::get_object() const {
492
return ObjectDB::get_instance(object);
493
}
494
495
ObjectID Signal::get_object_id() const {
496
return object;
497
}
498
499
StringName Signal::get_name() const {
500
return name;
501
}
502
503
bool Signal::operator==(const Signal &p_signal) const {
504
return object == p_signal.object && name == p_signal.name;
505
}
506
507
bool Signal::operator!=(const Signal &p_signal) const {
508
return object != p_signal.object || name != p_signal.name;
509
}
510
511
bool Signal::operator<(const Signal &p_signal) const {
512
if (object == p_signal.object) {
513
return name < p_signal.name;
514
} else {
515
return object < p_signal.object;
516
}
517
}
518
519
Signal::operator String() const {
520
Object *base = get_object();
521
if (base) {
522
String class_name = base->get_class();
523
Ref<Script> script = base->get_script();
524
if (script.is_valid() && script->get_path().is_resource_file()) {
525
class_name += "(" + script->get_path().get_file() + ")";
526
}
527
return class_name + "::[signal]" + String(name);
528
} else {
529
return "null::[signal]" + String(name);
530
}
531
}
532
533
Error Signal::emit(const Variant **p_arguments, int p_argcount) const {
534
Object *obj = ObjectDB::get_instance(object);
535
if (!obj) {
536
return ERR_INVALID_DATA;
537
}
538
539
return obj->emit_signalp(name, p_arguments, p_argcount);
540
}
541
542
Error Signal::connect(const Callable &p_callable, uint32_t p_flags) {
543
Object *obj = get_object();
544
ERR_FAIL_NULL_V(obj, ERR_UNCONFIGURED);
545
546
return obj->connect(name, p_callable, p_flags);
547
}
548
549
void Signal::disconnect(const Callable &p_callable) {
550
Object *obj = get_object();
551
ERR_FAIL_NULL(obj);
552
obj->disconnect(name, p_callable);
553
}
554
555
bool Signal::is_connected(const Callable &p_callable) const {
556
Object *obj = get_object();
557
ERR_FAIL_NULL_V(obj, false);
558
559
return obj->is_connected(name, p_callable);
560
}
561
562
bool Signal::has_connections() const {
563
Object *obj = get_object();
564
ERR_FAIL_NULL_V(obj, false);
565
566
return obj->has_connections(name);
567
}
568
569
Array Signal::get_connections() const {
570
Object *obj = get_object();
571
if (!obj) {
572
return Array();
573
}
574
575
List<Object::Connection> connections;
576
obj->get_signal_connection_list(name, &connections);
577
578
Array arr;
579
for (const Object::Connection &E : connections) {
580
arr.push_back(E);
581
}
582
return arr;
583
}
584
585
Signal::Signal(const Object *p_object, const StringName &p_name) {
586
ERR_FAIL_NULL_MSG(p_object, "Object argument to Signal constructor must be non-null.");
587
588
object = p_object->get_instance_id();
589
name = p_name;
590
}
591
592
Signal::Signal(ObjectID p_object, const StringName &p_name) {
593
object = p_object;
594
name = p_name;
595
}
596
597
bool CallableComparator::operator()(const Variant &p_l, const Variant &p_r) const {
598
const Variant *args[2] = { &p_l, &p_r };
599
Callable::CallError err;
600
Variant res;
601
func.callp(args, 2, res, err);
602
ERR_FAIL_COND_V_MSG(err.error != Callable::CallError::CALL_OK, false,
603
"Error calling compare method: " + Variant::get_callable_error_text(func, args, 2, err));
604
return res;
605
}
606
607