Skip to content

Commit f8c48a4

Browse files
committed
Implement callable_mp() and callable_mp_static()
1 parent bfc9e0b commit f8c48a4

File tree

10 files changed

+545
-0
lines changed

10 files changed

+545
-0
lines changed

gdextension/gdextension_interface.h

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,47 @@ typedef struct {
343343
GDExtensionVariantPtr *default_arguments;
344344
} GDExtensionClassMethodInfo;
345345

346+
typedef void (*GDExtensionCallableCustomCall)(void *callable_userdata, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error);
347+
typedef GDExtensionBool (*GDExtensionCallableCustomIsValid)(void *callable_userdata);
348+
typedef void (*GDExtensionCallableCustomFree)(void *callable_userdata);
349+
350+
typedef uint32_t (*GDExtensionCallableCustomHash)(void *callable_userdata);
351+
typedef GDExtensionBool (*GDExtensionCallableCustomEqual)(void *callable_userdata_a, void *callable_userdata_b);
352+
typedef GDExtensionBool (*GDExtensionCallableCustomLessThan)(void *callable_userdata_a, void *callable_userdata_b);
353+
354+
typedef void (*GDExtensionCallableCustomToString)(void *callable_userdata, GDExtensionBool *r_is_valid, GDExtensionStringPtr r_out);
355+
356+
typedef struct {
357+
/* Only `call_func` and `token` are strictly required, however, `object` should be passed if its not a static method.
358+
*
359+
* `token` should point to an address that uniquely identifies the GDExtension (for example, the
360+
* `GDExtensionClassLibraryPtr` passed to the entry symbol function.
361+
*
362+
* `hash_func`, `equal_func`, and `less_than_func` are optional. If not provided both `call_func` and
363+
* `callable_userdata` together are used as the identity of the callable for hashing and comparison purposes.
364+
*
365+
* The hash returned by `hash_func` is cached, `hash_func` will not be called more than once per callable.
366+
*
367+
* `is_valid_func` is necessary if the validity of the callable can change before destruction.
368+
*
369+
* `free_func` is necessary if `callable_userdata` needs to be cleaned up when the callable is freed.
370+
*/
371+
void *callable_userdata;
372+
void *token;
373+
374+
GDExtensionObjectPtr object;
375+
376+
GDExtensionCallableCustomCall call_func;
377+
GDExtensionCallableCustomIsValid is_valid_func;
378+
GDExtensionCallableCustomFree free_func;
379+
380+
GDExtensionCallableCustomHash hash_func;
381+
GDExtensionCallableCustomEqual equal_func;
382+
GDExtensionCallableCustomLessThan less_than_func;
383+
384+
GDExtensionCallableCustomToString to_string_func;
385+
} GDExtensionCallableCustomInfo;
386+
346387
/* SCRIPT INSTANCE EXTENSION */
347388

348389
typedef void *GDExtensionScriptInstanceDataPtr; // Pointer to custom ScriptInstance native implementation.
@@ -1985,6 +2026,34 @@ typedef void (*GDExtensionInterfaceRefSetObject)(GDExtensionRefPtr p_ref, GDExte
19852026
*/
19862027
typedef GDExtensionScriptInstancePtr (*GDExtensionInterfaceScriptInstanceCreate)(const GDExtensionScriptInstanceInfo *p_info, GDExtensionScriptInstanceDataPtr p_instance_data);
19872028

2029+
/* INTERFACE: Callable */
2030+
2031+
/**
2032+
* @name callable_custom_create
2033+
* @since 4.2
2034+
*
2035+
* Creates a custom Callable object from a function pointer.
2036+
*
2037+
* Provided struct can be safely freed once the function returns.
2038+
*
2039+
* @param r_callable A pointer that will receive the new Callable.
2040+
* @param p_callable_custom_info The info required to construct a Callable.
2041+
*/
2042+
typedef void (*GDExtensionInterfaceCallableCustomCreate)(GDExtensionUninitializedTypePtr r_callable, GDExtensionCallableCustomInfo *p_callable_custom_info);
2043+
2044+
/**
2045+
* @name callable_custom_get_userdata
2046+
* @since 4.2
2047+
*
2048+
* Retrieves the userdata pointer from a custom Callable.
2049+
*
2050+
* If the Callable is not a custom Callable or the token does not match the one provided to callable_custom_create() via GDExtensionCallableCustomInfo then NULL will be returned.
2051+
*
2052+
* @param p_callable A pointer to a Callable.
2053+
* @param p_token A pointer to an address that uniquely identifies the GDExtension.
2054+
*/
2055+
typedef void *(*GDExtensionInterfaceCallableCustomGetUserData)(GDExtensionConstTypePtr p_callable, void *p_token);
2056+
19882057
/* INTERFACE: ClassDB */
19892058

19902059
/**

include/godot_cpp/core/binder_common.hpp

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,60 @@ void call_with_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) co
276276
(void)p_args;
277277
}
278278

279+
template <class T, class... P>
280+
void call_with_variant_args(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, int p_argcount, GDExtensionCallError &r_error) {
281+
#ifdef DEBUG_ENABLED
282+
if ((size_t)p_argcount > sizeof...(P)) {
283+
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
284+
r_error.argument = (int32_t)sizeof...(P);
285+
return;
286+
}
287+
288+
if ((size_t)p_argcount < sizeof...(P)) {
289+
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
290+
r_error.argument = (int32_t)sizeof...(P);
291+
return;
292+
}
293+
#endif
294+
call_with_variant_args_helper<T, P...>(p_instance, p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
295+
}
296+
297+
template <class T, class R, class... P>
298+
void call_with_variant_args_ret(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
299+
#ifdef DEBUG_ENABLED
300+
if ((size_t)p_argcount > sizeof...(P)) {
301+
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
302+
r_error.argument = (int32_t)sizeof...(P);
303+
return;
304+
}
305+
306+
if ((size_t)p_argcount < sizeof...(P)) {
307+
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
308+
r_error.argument = (int32_t)sizeof...(P);
309+
return;
310+
}
311+
#endif
312+
call_with_variant_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
313+
}
314+
315+
template <class T, class R, class... P>
316+
void call_with_variant_args_retc(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
317+
#ifdef DEBUG_ENABLED
318+
if ((size_t)p_argcount > sizeof...(P)) {
319+
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
320+
r_error.argument = (int32_t)sizeof...(P);
321+
return;
322+
}
323+
324+
if ((size_t)p_argcount < sizeof...(P)) {
325+
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
326+
r_error.argument = (int32_t)sizeof...(P);
327+
return;
328+
}
329+
#endif
330+
call_with_variant_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
331+
}
332+
279333
template <class T, class... P>
280334
void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const GDExtensionConstVariantPtr *p_args, int p_argcount, GDExtensionCallError &r_error, const std::vector<Variant> &default_values) {
281335
#ifdef DEBUG_ENABLED
@@ -538,6 +592,42 @@ void call_with_ptr_args_static_method(void (*p_method)(P...), const GDExtensionC
538592
call_with_ptr_args_static_method_helper<P...>(p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
539593
}
540594

595+
template <class R, class... P>
596+
void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
597+
#ifdef DEBUG_ENABLED
598+
if ((size_t)p_argcount > sizeof...(P)) {
599+
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
600+
r_error.argument = (int32_t)sizeof...(P);
601+
return;
602+
}
603+
604+
if ((size_t)p_argcount < sizeof...(P)) {
605+
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
606+
r_error.argument = (int32_t)sizeof...(P);
607+
return;
608+
}
609+
#endif
610+
call_with_variant_args_static_ret<R, P...>(p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
611+
}
612+
613+
template <class... P>
614+
void call_with_variant_args_static_ret(void (*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, GDExtensionCallError &r_error) {
615+
#ifdef DEBUG_ENABLED
616+
if ((size_t)p_argcount > sizeof...(P)) {
617+
r_error.error = GDEXTENSION_CALL_ERROR_TOO_MANY_ARGUMENTS;
618+
r_error.argument = (int32_t)sizeof...(P);
619+
return;
620+
}
621+
622+
if ((size_t)p_argcount < sizeof...(P)) {
623+
r_error.error = GDEXTENSION_CALL_ERROR_TOO_FEW_ARGUMENTS;
624+
r_error.argument = (int32_t)sizeof...(P);
625+
return;
626+
}
627+
#endif
628+
call_with_variant_args_static<P...>(p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
629+
}
630+
541631
template <class R, class... P, size_t... Is>
542632
void call_with_variant_args_static_ret(R (*p_method)(P...), const Variant **p_args, Variant &r_ret, GDExtensionCallError &r_error, IndexSequence<Is...>) {
543633
r_error.error = GDEXTENSION_CALL_OK;

include/godot_cpp/core/class_db.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@
3838
#include <godot_cpp/core/method_bind.hpp>
3939
#include <godot_cpp/core/object.hpp>
4040

41+
// Makes callable_mp readily available in all classes connecting signals.
42+
// Needs to come after method_bind and object have been included.
43+
#include <godot_cpp/variant/callable_method_pointer.hpp>
44+
4145
#include <list>
4246
#include <set>
4347
#include <string>

include/godot_cpp/godot.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ extern "C" GDExtensionInterfaceObjectGetClassName gdextension_interface_object_g
163163
extern "C" GDExtensionInterfaceObjectCastTo gdextension_interface_object_cast_to;
164164
extern "C" GDExtensionInterfaceObjectGetInstanceFromId gdextension_interface_object_get_instance_from_id;
165165
extern "C" GDExtensionInterfaceObjectGetInstanceId gdextension_interface_object_get_instance_id;
166+
extern "C" GDExtensionInterfaceCallableCustomCreate gdextension_interface_callable_custom_create;
166167
extern "C" GDExtensionInterfaceRefGetObject gdextension_interface_ref_get_object;
167168
extern "C" GDExtensionInterfaceRefSetObject gdextension_interface_ref_set_object;
168169
extern "C" GDExtensionInterfaceScriptInstanceCreate gdextension_interface_script_instance_create;

0 commit comments

Comments
 (0)