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 "callable_bind.h"
34#include "core/object/message_queue.h"
35#include "core/object/object.h"
36#include "core/object/ref_counted.h"
37#include "core/object/script_language.h"
38
39void Callable::call_deferredp(const Variant **p_arguments, int p_argcount) const {
40 MessageQueue::get_singleton()->push_callablep(*this, p_arguments, p_argcount);
41}
42
43void 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 custom->call(p_arguments, p_argcount, r_return_value, r_call_error);
51 } else {
52 Object *obj = ObjectDB::get_instance(ObjectID(object));
53#ifdef DEBUG_ENABLED
54 if (!obj) {
55 r_call_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL;
56 r_call_error.argument = 0;
57 r_call_error.expected = 0;
58 r_return_value = Variant();
59 return;
60 }
61#endif
62 r_return_value = obj->callp(method, p_arguments, p_argcount, r_call_error);
63 }
64}
65
66Variant Callable::callv(const Array &p_arguments) const {
67 int argcount = p_arguments.size();
68 const Variant **argptrs = nullptr;
69 if (argcount) {
70 argptrs = (const Variant **)alloca(sizeof(Variant *) * argcount);
71 for (int i = 0; i < argcount; i++) {
72 argptrs[i] = &p_arguments[i];
73 }
74 }
75 CallError ce;
76 Variant ret;
77 callp(argptrs, argcount, ret, ce);
78 return ret;
79}
80
81Error Callable::rpcp(int p_id, const Variant **p_arguments, int p_argcount, CallError &r_call_error) const {
82 if (is_null()) {
83 r_call_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL;
84 r_call_error.argument = 0;
85 r_call_error.expected = 0;
86 return ERR_UNCONFIGURED;
87 } else if (!is_custom()) {
88 r_call_error.error = CallError::CALL_ERROR_INVALID_METHOD;
89 r_call_error.argument = 0;
90 r_call_error.expected = 0;
91 return ERR_UNCONFIGURED;
92 } else {
93 return custom->rpc(p_id, p_arguments, p_argcount, r_call_error);
94 }
95}
96
97Callable Callable::bindp(const Variant **p_arguments, int p_argcount) const {
98 Vector<Variant> args;
99 args.resize(p_argcount);
100 for (int i = 0; i < p_argcount; i++) {
101 args.write[i] = *p_arguments[i];
102 }
103 return Callable(memnew(CallableCustomBind(*this, args)));
104}
105
106Callable Callable::bindv(const Array &p_arguments) {
107 if (p_arguments.is_empty()) {
108 return *this; // No point in creating a new callable if nothing is bound.
109 }
110
111 Vector<Variant> args;
112 args.resize(p_arguments.size());
113 for (int i = 0; i < p_arguments.size(); i++) {
114 args.write[i] = p_arguments[i];
115 }
116 return Callable(memnew(CallableCustomBind(*this, args)));
117}
118
119Callable Callable::unbind(int p_argcount) const {
120 ERR_FAIL_COND_V_MSG(p_argcount <= 0, Callable(*this), "Amount of unbind() arguments must be 1 or greater.");
121 return Callable(memnew(CallableCustomUnbind(*this, p_argcount)));
122}
123
124bool Callable::is_valid() const {
125 if (is_custom()) {
126 return get_custom()->is_valid();
127 } else {
128 return get_object() && get_object()->has_method(get_method());
129 }
130}
131
132Object *Callable::get_object() const {
133 if (is_null()) {
134 return nullptr;
135 } else if (is_custom()) {
136 return ObjectDB::get_instance(custom->get_object());
137 } else {
138 return ObjectDB::get_instance(ObjectID(object));
139 }
140}
141
142ObjectID Callable::get_object_id() const {
143 if (is_null()) {
144 return ObjectID();
145 } else if (is_custom()) {
146 return custom->get_object();
147 } else {
148 return ObjectID(object);
149 }
150}
151
152StringName Callable::get_method() const {
153 if (is_custom()) {
154 return get_custom()->get_method();
155 }
156 return method;
157}
158
159int Callable::get_bound_arguments_count() const {
160 if (!is_null() && is_custom()) {
161 return custom->get_bound_arguments_count();
162 } else {
163 return 0;
164 }
165}
166
167void Callable::get_bound_arguments_ref(Vector<Variant> &r_arguments, int &r_argcount) const {
168 if (!is_null() && is_custom()) {
169 custom->get_bound_arguments(r_arguments, r_argcount);
170 } else {
171 r_arguments.clear();
172 r_argcount = 0;
173 }
174}
175
176Array Callable::get_bound_arguments() const {
177 Vector<Variant> arr;
178 int ac;
179 get_bound_arguments_ref(arr, ac);
180 Array ret;
181 ret.resize(arr.size());
182 for (int i = 0; i < arr.size(); i++) {
183 ret[i] = arr[i];
184 }
185 return ret;
186}
187
188CallableCustom *Callable::get_custom() const {
189 ERR_FAIL_COND_V_MSG(!is_custom(), nullptr,
190 vformat("Can't get custom on non-CallableCustom \"%s\".", operator String()));
191 return custom;
192}
193
194const Callable *Callable::get_base_comparator() const {
195 const Callable *comparator = nullptr;
196 if (is_custom()) {
197 comparator = custom->get_base_comparator();
198 }
199 if (comparator) {
200 return comparator;
201 } else {
202 return this;
203 }
204}
205
206uint32_t Callable::hash() const {
207 if (is_custom()) {
208 return custom->hash();
209 } else {
210 uint32_t hash = method.hash();
211 hash = hash_murmur3_one_64(object, hash);
212 return hash_fmix32(hash);
213 }
214}
215
216bool Callable::operator==(const Callable &p_callable) const {
217 bool custom_a = is_custom();
218 bool custom_b = p_callable.is_custom();
219
220 if (custom_a == custom_b) {
221 if (custom_a) {
222 if (custom == p_callable.custom) {
223 return true; //same pointer, don't even compare
224 }
225
226 CallableCustom::CompareEqualFunc eq_a = custom->get_compare_equal_func();
227 CallableCustom::CompareEqualFunc eq_b = p_callable.custom->get_compare_equal_func();
228 if (eq_a == eq_b) {
229 return eq_a(custom, p_callable.custom);
230 } else {
231 return false;
232 }
233 } else {
234 return object == p_callable.object && method == p_callable.method;
235 }
236 } else {
237 return false;
238 }
239}
240
241bool Callable::operator!=(const Callable &p_callable) const {
242 return !(*this == p_callable);
243}
244
245bool Callable::operator<(const Callable &p_callable) const {
246 bool custom_a = is_custom();
247 bool custom_b = p_callable.is_custom();
248
249 if (custom_a == custom_b) {
250 if (custom_a) {
251 if (custom == p_callable.custom) {
252 return false; //same pointer, don't even compare
253 }
254
255 CallableCustom::CompareLessFunc less_a = custom->get_compare_less_func();
256 CallableCustom::CompareLessFunc less_b = p_callable.custom->get_compare_less_func();
257 if (less_a == less_b) {
258 return less_a(custom, p_callable.custom);
259 } else {
260 return less_a < less_b; //it's something..
261 }
262
263 } else {
264 if (object == p_callable.object) {
265 return method < p_callable.method;
266 } else {
267 return object < p_callable.object;
268 }
269 }
270 } else {
271 return int(custom_a ? 1 : 0) < int(custom_b ? 1 : 0);
272 }
273}
274
275void Callable::operator=(const Callable &p_callable) {
276 if (is_custom()) {
277 if (p_callable.is_custom()) {
278 if (custom == p_callable.custom) {
279 return;
280 }
281 }
282
283 if (custom->ref_count.unref()) {
284 memdelete(custom);
285 }
286 }
287
288 if (p_callable.is_custom()) {
289 method = StringName();
290 if (!p_callable.custom->ref_count.ref()) {
291 object = 0;
292 } else {
293 object = 0;
294 custom = p_callable.custom;
295 }
296 } else {
297 method = p_callable.method;
298 object = p_callable.object;
299 }
300}
301
302Callable::operator String() const {
303 if (is_custom()) {
304 return custom->get_as_text();
305 } else {
306 if (is_null()) {
307 return "null::null";
308 }
309
310 Object *base = get_object();
311 if (base) {
312 String class_name = base->get_class();
313 Ref<Script> script = base->get_script();
314 if (script.is_valid() && script->get_path().is_resource_file()) {
315 class_name += "(" + script->get_path().get_file() + ")";
316 }
317 return class_name + "::" + String(method);
318 } else {
319 return "null::" + String(method);
320 }
321 }
322}
323
324Callable::Callable(const Object *p_object, const StringName &p_method) {
325 if (p_method == StringName()) {
326 object = 0;
327 ERR_FAIL_MSG("Method argument to Callable constructor must be a non-empty string");
328 }
329 if (p_object == nullptr) {
330 object = 0;
331 ERR_FAIL_MSG("Object argument to Callable constructor must be non-null");
332 }
333
334 object = p_object->get_instance_id();
335 method = p_method;
336}
337
338Callable::Callable(ObjectID p_object, const StringName &p_method) {
339 if (p_method == StringName()) {
340 object = 0;
341 ERR_FAIL_MSG("Method argument to Callable constructor must be a non-empty string");
342 }
343
344 object = p_object;
345 method = p_method;
346}
347
348Callable::Callable(CallableCustom *p_custom) {
349 if (p_custom->referenced) {
350 object = 0;
351 ERR_FAIL_MSG("Callable custom is already referenced");
352 }
353 p_custom->referenced = true;
354 object = 0; //ensure object is all zero, since pointer may be 32 bits
355 custom = p_custom;
356}
357
358Callable::Callable(const Callable &p_callable) {
359 if (p_callable.is_custom()) {
360 if (!p_callable.custom->ref_count.ref()) {
361 object = 0;
362 } else {
363 object = 0;
364 custom = p_callable.custom;
365 }
366 } else {
367 method = p_callable.method;
368 object = p_callable.object;
369 }
370}
371
372Callable::~Callable() {
373 if (is_custom()) {
374 if (custom->ref_count.unref()) {
375 memdelete(custom);
376 }
377 }
378}
379
380bool CallableCustom::is_valid() const {
381 // Sensible default implementation so most custom callables don't need their own.
382 return ObjectDB::get_instance(get_object());
383}
384
385StringName CallableCustom::get_method() const {
386 ERR_FAIL_V_MSG(StringName(), vformat("Can't get method on CallableCustom \"%s\".", get_as_text()));
387}
388
389Error CallableCustom::rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const {
390 r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
391 r_call_error.argument = 0;
392 r_call_error.expected = 0;
393 return ERR_UNCONFIGURED;
394}
395
396const Callable *CallableCustom::get_base_comparator() const {
397 return nullptr;
398}
399
400int CallableCustom::get_bound_arguments_count() const {
401 return 0;
402}
403
404void CallableCustom::get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const {
405 r_arguments = Vector<Variant>();
406 r_argcount = 0;
407}
408
409CallableCustom::CallableCustom() {
410 ref_count.init();
411}
412
413//////////////////////////////////
414
415Object *Signal::get_object() const {
416 return ObjectDB::get_instance(object);
417}
418
419ObjectID Signal::get_object_id() const {
420 return object;
421}
422
423StringName Signal::get_name() const {
424 return name;
425}
426
427bool Signal::operator==(const Signal &p_signal) const {
428 return object == p_signal.object && name == p_signal.name;
429}
430
431bool Signal::operator!=(const Signal &p_signal) const {
432 return object != p_signal.object || name != p_signal.name;
433}
434
435bool Signal::operator<(const Signal &p_signal) const {
436 if (object == p_signal.object) {
437 return name < p_signal.name;
438 } else {
439 return object < p_signal.object;
440 }
441}
442
443Signal::operator String() const {
444 Object *base = get_object();
445 if (base) {
446 String class_name = base->get_class();
447 Ref<Script> script = base->get_script();
448 if (script.is_valid() && script->get_path().is_resource_file()) {
449 class_name += "(" + script->get_path().get_file() + ")";
450 }
451 return class_name + "::[signal]" + String(name);
452 } else {
453 return "null::[signal]" + String(name);
454 }
455}
456
457Error Signal::emit(const Variant **p_arguments, int p_argcount) const {
458 Object *obj = ObjectDB::get_instance(object);
459 if (!obj) {
460 return ERR_INVALID_DATA;
461 }
462
463 return obj->emit_signalp(name, p_arguments, p_argcount);
464}
465
466Error Signal::connect(const Callable &p_callable, uint32_t p_flags) {
467 Object *obj = get_object();
468 ERR_FAIL_NULL_V(obj, ERR_UNCONFIGURED);
469
470 return obj->connect(name, p_callable, p_flags);
471}
472
473void Signal::disconnect(const Callable &p_callable) {
474 Object *obj = get_object();
475 ERR_FAIL_NULL(obj);
476 obj->disconnect(name, p_callable);
477}
478
479bool Signal::is_connected(const Callable &p_callable) const {
480 Object *obj = get_object();
481 ERR_FAIL_NULL_V(obj, false);
482
483 return obj->is_connected(name, p_callable);
484}
485
486Array Signal::get_connections() const {
487 Object *obj = get_object();
488 if (!obj) {
489 return Array();
490 }
491
492 List<Object::Connection> connections;
493 obj->get_signal_connection_list(name, &connections);
494
495 Array arr;
496 for (const Object::Connection &E : connections) {
497 arr.push_back(E);
498 }
499 return arr;
500}
501
502Signal::Signal(const Object *p_object, const StringName &p_name) {
503 ERR_FAIL_NULL_MSG(p_object, "Object argument to Signal constructor must be non-null.");
504
505 object = p_object->get_instance_id();
506 name = p_name;
507}
508
509Signal::Signal(ObjectID p_object, const StringName &p_name) {
510 object = p_object;
511 name = p_name;
512}
513
514bool CallableComparator::operator()(const Variant &p_l, const Variant &p_r) const {
515 const Variant *args[2] = { &p_l, &p_r };
516 Callable::CallError err;
517 Variant res;
518 func.callp(args, 2, res, err);
519 ERR_FAIL_COND_V_MSG(err.error != Callable::CallError::CALL_OK, false,
520 "Error calling compare method: " + Variant::get_callable_error_text(func, args, 2, err));
521 return res;
522}
523