From d25fe05b1e5ddd4e57c90aa7562b699dfb2f3553 Mon Sep 17 00:00:00 2001 From: nlupugla Date: Sat, 21 Sep 2024 11:38:25 -0400 Subject: [PATCH 1/3] Added Structs to core. --- SConstruct | 2 + core/core_bind.cpp | 77 +++++ core/core_bind.h | 8 + core/object/class_db.cpp | 73 +++++ core/object/class_db.h | 10 + core/object/method_info.cpp | 99 ++++++ core/object/method_info.h | 137 ++++++++ core/object/object.cpp | 143 +++----- core/object/object.h | 260 +-------------- core/object/property_info.cpp | 90 +++++ core/object/property_info.h | 176 ++++++++++ core/string/ustring.cpp | 6 +- core/variant/array.cpp | 324 ++++++++++++++---- core/variant/array.h | 28 ++ core/variant/container_type_validate.h | 151 +++++++-- core/variant/dictionary.cpp | 123 +++---- core/variant/dictionary.h | 1 + core/variant/struct.h | 146 +++++++++ core/variant/struct_generator.cpp | 84 +++++ core/variant/struct_generator.h | 305 +++++++++++++++++ core/variant/typed_array.h | 51 ++- core/variant/variant.cpp | 17 +- core/variant/variant.h | 3 + core/variant/variant_construct.cpp | 1 + core/variant/variant_construct.h | 87 +++++ core/variant/variant_setget.cpp | 78 +++-- scene/resources/2d/tile_set.h | 4 +- tests/core/variant/test_struct.h | 434 +++++++++++++++++++++++++ tests/test_main.cpp | 1 + 29 files changed, 2403 insertions(+), 516 deletions(-) create mode 100644 core/object/method_info.cpp create mode 100644 core/object/method_info.h create mode 100644 core/object/property_info.cpp create mode 100644 core/object/property_info.h create mode 100644 core/variant/struct.h create mode 100644 core/variant/struct_generator.cpp create mode 100644 core/variant/struct_generator.h create mode 100644 tests/core/variant/test_struct.h diff --git a/SConstruct b/SConstruct index ee34d421e071..a07771623761 100644 --- a/SConstruct +++ b/SConstruct @@ -858,6 +858,8 @@ if env.msvc and not methods.using_clang(env): # MSVC ] ) + env.Append(CCFLAGS=["/permissive-"]) + if env["werror"]: env.Append(CCFLAGS=["/WX"]) env.Append(LINKFLAGS=["/WX"]) diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 967a7fba7575..12a5d6aeaa5e 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -42,6 +42,7 @@ #include "core/math/geometry_3d.h" #include "core/os/keyboard.h" #include "core/os/thread_safe.h" +#include "core/variant/struct.h" #include "core/variant/typed_array.h" namespace core_bind { @@ -1462,6 +1463,15 @@ Dictionary ClassDB::class_get_signal(const StringName &p_class, const StringName } } +//Struct ClassDB::class_get_signal_as_struct(const StringName &p_class, const StringName &p_signal) const { +// MethodInfo signal; +// if (::ClassDB::get_signal(p_class, p_signal, &signal)) { +// return Struct(signal); +// } else { +// return Struct(); +// } +//} + TypedArray ClassDB::class_get_signal_list(const StringName &p_class, bool p_no_inheritance) const { List signals; ::ClassDB::get_signal_list(p_class, &signals, p_no_inheritance); @@ -1474,6 +1484,12 @@ TypedArray ClassDB::class_get_signal_list(const StringName &p_class, return ret; } +//TypedArray> ClassDB::class_get_signal_list_as_structs(const StringName &p_class, bool p_no_inheritance) const { +// List signals; +// ::ClassDB::get_signal_list(p_class, &signals, p_no_inheritance); +// return TypedArray>(&signals); +//} + TypedArray ClassDB::class_get_property_list(const StringName &p_class, bool p_no_inheritance) const { List plist; ::ClassDB::get_property_list(p_class, &plist, p_no_inheritance); @@ -1485,6 +1501,12 @@ TypedArray ClassDB::class_get_property_list(const StringName &p_clas return ret; } +//TypedArray> ClassDB::class_get_property_list_as_structs(const StringName &p_class, bool p_no_inheritance) const { +// List plist; +// ::ClassDB::get_property_list(p_class, &plist, p_no_inheritance); +// return TypedArray>(&plist); +//} + StringName ClassDB::class_get_property_getter(const StringName &p_class, const StringName &p_property) { return ::ClassDB::get_property_getter(p_class, p_property); } @@ -1545,6 +1567,12 @@ TypedArray ClassDB::class_get_method_list(const StringName &p_class, return ret; } +//TypedArray> ClassDB::class_get_method_list_as_structs(const StringName &p_class, bool p_no_inheritance) const { +// List methods; +// ::ClassDB::get_method_list(p_class, &methods, p_no_inheritance); +// return TypedArray>(&methods); +//} + Variant ClassDB::class_call_static(const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) { if (p_argcount < 2) { r_call_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; @@ -1629,6 +1657,47 @@ bool ClassDB::is_class_enum_bitfield(const StringName &p_class, const StringName return ::ClassDB::is_enum_bitfield(p_class, p_enum, p_no_inheritance); } +bool ClassDB::class_has_struct(const StringName &p_class, const StringName &p_struct, bool p_no_inheritance) const { + return ::ClassDB::get_struct_info(p_class, p_struct, p_no_inheritance) != nullptr; +} + +TypedArray ClassDB::class_get_struct_list(const StringName &p_class, bool p_no_inheritance) const { + List structs; + TypedArray ret; + ::ClassDB::get_struct_list(p_class, &structs, p_no_inheritance); + for (const StructInfo &struct_info : structs) { + Dictionary struct_dict; + for (int i = 0; i < struct_info.count; i++) { + Dictionary member_dict; + member_dict[SNAME("name")] = struct_info.names[i]; + member_dict[SNAME("type")] = struct_info.types[i]; + member_dict[SNAME("class_name")] = struct_info.class_names[i]; + member_dict[SNAME("default_value")] = struct_info.default_values[i]; + struct_dict[struct_info.name] = member_dict; + } + ret.push_back(struct_dict); + } + return ret; +} + +TypedArray ClassDB::class_get_struct_members(const StringName &p_class, const StringName &p_struct) const { + // TODO: this should return an array of structs if possible without circular reference + TypedArray ret; + const StructInfo *struct_info = ::ClassDB::get_struct_info(p_class, p_struct); + if (!struct_info) { + return ret; // TODO: should this be an error? + } + for (int i = 0; i < struct_info->count; i++) { + Dictionary dict; + dict[SNAME("name")] = struct_info->names[i]; + dict[SNAME("type")] = struct_info->types[i]; + dict[SNAME("class_name")] = struct_info->class_names[i]; + dict[SNAME("default_value")] = struct_info->default_values[i]; + ret.push_back(dict); + } + return ret; +} + bool ClassDB::is_class_enabled(const StringName &p_class) const { return ::ClassDB::is_class_enabled(p_class); } @@ -1670,9 +1739,12 @@ void ClassDB::_bind_methods() { ::ClassDB::bind_method(D_METHOD("class_has_signal", "class", "signal"), &ClassDB::class_has_signal); ::ClassDB::bind_method(D_METHOD("class_get_signal", "class", "signal"), &ClassDB::class_get_signal); + //::ClassDB::bind_method(D_METHOD("class_get_signal_as_struct", "class", "signal"), &ClassDB::class_get_signal_as_struct); ::ClassDB::bind_method(D_METHOD("class_get_signal_list", "class", "no_inheritance"), &ClassDB::class_get_signal_list, DEFVAL(false)); + //::ClassDB::bind_method(D_METHOD("class_get_signal_list_as_structs", "class", "no_inheritance"), &ClassDB::class_get_signal_list_as_structs, DEFVAL(false)); ::ClassDB::bind_method(D_METHOD("class_get_property_list", "class", "no_inheritance"), &ClassDB::class_get_property_list, DEFVAL(false)); + //::ClassDB::bind_method(D_METHOD("class_get_property_list_as_structs", "class", "no_inheritance"), &ClassDB::class_get_property_list_as_structs, DEFVAL(false)); ::ClassDB::bind_method(D_METHOD("class_get_property_getter", "class", "property"), &ClassDB::class_get_property_getter); ::ClassDB::bind_method(D_METHOD("class_get_property_setter", "class", "property"), &ClassDB::class_get_property_setter); ::ClassDB::bind_method(D_METHOD("class_get_property", "object", "property"), &ClassDB::class_get_property); @@ -1685,6 +1757,7 @@ void ClassDB::_bind_methods() { ::ClassDB::bind_method(D_METHOD("class_get_method_argument_count", "class", "method", "no_inheritance"), &ClassDB::class_get_method_argument_count, DEFVAL(false)); ::ClassDB::bind_method(D_METHOD("class_get_method_list", "class", "no_inheritance"), &ClassDB::class_get_method_list, DEFVAL(false)); + //::ClassDB::bind_method(D_METHOD("class_get_method_list_as_structs", "class", "no_inheritance"), &ClassDB::class_get_method_list_as_structs, DEFVAL(false)); ::ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "class_call_static", &ClassDB::class_call_static, MethodInfo("class_call_static", PropertyInfo(Variant::STRING_NAME, "class"), PropertyInfo(Variant::STRING_NAME, "method"))); @@ -1700,6 +1773,10 @@ void ClassDB::_bind_methods() { ::ClassDB::bind_method(D_METHOD("is_class_enum_bitfield", "class", "enum", "no_inheritance"), &ClassDB::is_class_enum_bitfield, DEFVAL(false)); + // ::ClassDB::bind_method(D_METHOD("class_has_struct", "class", "struct", "no_inheritance"), &ClassDB::class_has_struct, DEFVAL(false)); + // ::ClassDB::bind_method(D_METHOD("class_get_struct_list", "class", "no_inheritance"), &ClassDB::class_get_struct_list, DEFVAL(false)); + // ::ClassDB::bind_method(D_METHOD("class_get_struct_members", "class", "struct"), &ClassDB::class_get_struct_members); + ::ClassDB::bind_method(D_METHOD("is_class_enabled", "class"), &ClassDB::is_class_enabled); BIND_ENUM_CONSTANT(API_CORE); diff --git a/core/core_bind.h b/core/core_bind.h index 3ae54017fe58..1116bd02b01d 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -471,9 +471,12 @@ class ClassDB : public Object { APIType class_get_api_type(const StringName &p_class) const; bool class_has_signal(const StringName &p_class, const StringName &p_signal) const; Dictionary class_get_signal(const StringName &p_class, const StringName &p_signal) const; + //Struct class_get_signal_as_struct(const StringName &p_class, const StringName &p_signal) const; TypedArray class_get_signal_list(const StringName &p_class, bool p_no_inheritance = false) const; + //TypedArray> class_get_signal_list_as_structs(const StringName &p_class, bool p_no_inheritance = false) const; TypedArray class_get_property_list(const StringName &p_class, bool p_no_inheritance = false) const; + //TypedArray> class_get_property_list_as_structs(const StringName &p_class, bool p_no_inheritance = false) const; StringName class_get_property_getter(const StringName &p_class, const StringName &p_property); StringName class_get_property_setter(const StringName &p_class, const StringName &p_property); Variant class_get_property(Object *p_object, const StringName &p_property) const; @@ -486,6 +489,7 @@ class ClassDB : public Object { int class_get_method_argument_count(const StringName &p_class, const StringName &p_method, bool p_no_inheritance = false) const; TypedArray class_get_method_list(const StringName &p_class, bool p_no_inheritance = false) const; + //TypedArray> class_get_method_list_as_structs(const StringName &p_class, bool p_no_inheritance = false) const; Variant class_call_static(const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error); PackedStringArray class_get_integer_constant_list(const StringName &p_class, bool p_no_inheritance = false) const; @@ -501,6 +505,10 @@ class ClassDB : public Object { bool is_class_enabled(const StringName &p_class) const; + bool class_has_struct(const StringName &p_class, const StringName &p_struct, bool p_no_inheritance = false) const; + TypedArray class_get_struct_list(const StringName &p_class, bool p_no_inheritance = false) const; + TypedArray class_get_struct_members(const StringName &p_class, const StringName &p_struct) const; + #ifdef TOOLS_ENABLED virtual void get_argument_options(const StringName &p_function, int p_idx, List *r_options) const override; #endif diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index d48e1a3622f6..86c0c2845e33 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -34,6 +34,7 @@ #include "core/io/resource_loader.h" #include "core/object/script_language.h" #include "core/os/mutex.h" +#include "core/variant/struct.h" #include "core/version.h" #define OBJTYPE_RLOCK RWLockRead _rw_lockr_(lock); @@ -505,6 +506,8 @@ uint32_t ClassDB::get_api_hash(APIType p_api) { hash = hash_murmur3_one_64(F.hint_string.hash(), hash); hash = hash_murmur3_one_64(F.usage, hash); } + + // TODO: do I need to incorporate the structs into the hash? } hash = hash_fmix32(hash); @@ -1335,6 +1338,67 @@ bool ClassDB::is_enum_bitfield(const StringName &p_class, const StringName &p_na return false; } +void ClassDB::bind_struct(const StringName &p_class_name, const StructInfo &p_struct_info) { + OBJTYPE_WLOCK; + + ClassInfo *type = classes.getptr(p_class_name); + + ERR_FAIL_NULL(type); + + if (type->struct_map.has(p_struct_info.name)) { + ERR_FAIL(); + } + + String struct_name = p_struct_info.name; + if (struct_name.contains(".")) { + struct_name = struct_name.get_slicec('.', 1); + } + + type->struct_map.insert(struct_name, p_struct_info); +} + +void ClassDB::get_struct_list(const StringName &p_class, List *r_structs, bool p_no_inheritance) { + OBJTYPE_RLOCK; + + ClassInfo *type = classes.getptr(p_class); + + while (type) { + for (const KeyValue &E : type->struct_map) { + r_structs->push_back(E.value); + } + + if (p_no_inheritance) { + break; + } + + type = type->inherits_ptr; + } +} + +const StructInfo *ClassDB::get_struct_info(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) { + OBJTYPE_RLOCK; + + ClassInfo *type = classes.getptr(p_class); + while (type) { + if (const StructInfo *info = type->struct_map.getptr(p_name)) { + return info; + } + if (p_no_inheritance) { + return nullptr; + } + type = type->inherits_ptr; + } + return nullptr; +} + +const StructInfo *ClassDB::get_struct_info(const String &p_qualified_name, bool p_no_inheritance) { + Vector names = String(p_qualified_name).split("."); // TODO: what about cases other than size == 2? + if (names.size() == 2) { + return ClassDB::get_struct_info(names[0], names[1]); + } + return nullptr; +} + void ClassDB::add_signal(const StringName &p_class, const MethodInfo &p_signal) { OBJTYPE_WLOCK; @@ -1447,6 +1511,15 @@ void ClassDB::add_property_array(const StringName &p_class, const StringName &p_ type->property_list.push_back(PropertyInfo(Variant::NIL, p_path, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, p_array_element_prefix)); } +// TODO: This probably isn't right, I just copied the function above. +void ClassDB::add_property_struct(const StringName &p_class, const StringName &p_path, const String &p_array_element_prefix) { + OBJTYPE_WLOCK; // TODO: I'm not sure what this does but it's in the one above so I figure I need it + ClassInfo *type = classes.getptr(p_class); + ERR_FAIL_NULL(type); + + type->property_list.push_back(PropertyInfo(Variant::NIL, p_path, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, p_array_element_prefix)); +} + // NOTE: For implementation simplicity reasons, this method doesn't allow setters to have optional arguments at the end. void ClassDB::add_property(const StringName &p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index) { lock.read_lock(); diff --git a/core/object/class_db.h b/core/object/class_db.h index 81100d7586b8..22515125de19 100644 --- a/core/object/class_db.h +++ b/core/object/class_db.h @@ -114,6 +114,7 @@ class ClassDB { }; HashMap enum_map; + HashMap struct_map; HashMap signal_map; List property_list; HashMap property_map; @@ -426,6 +427,7 @@ class ClassDB { static void add_property_subgroup(const StringName &p_class, const String &p_name, const String &p_prefix = "", int p_indent_depth = 0); static void add_property_array_count(const StringName &p_class, const String &p_label, const StringName &p_count_property, const StringName &p_count_setter, const StringName &p_count_getter, const String &p_array_element_prefix, uint32_t p_count_usage = PROPERTY_USAGE_DEFAULT); static void add_property_array(const StringName &p_class, const StringName &p_path, const String &p_array_element_prefix); + static void add_property_struct(const StringName &p_class, const StringName &p_path, const String &p_array_element_prefix); static void add_property(const StringName &p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index = -1); static void set_property_default_value(const StringName &p_class, const StringName &p_name, const Variant &p_default); static void add_linked_property(const StringName &p_class, const String &p_property, const String &p_linked_property); @@ -467,6 +469,11 @@ class ClassDB { static bool has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false); static bool is_enum_bitfield(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false); + static void bind_struct(const StringName &p_class, const StructInfo &p_struct_info); + static void get_struct_list(const StringName &p_class, List *r_structs, bool p_no_inheritance = false); + static const StructInfo *get_struct_info(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false); + static const StructInfo *get_struct_info(const String &p_qualified_name, bool p_no_inheritance = false); + static void set_method_error_return_values(const StringName &p_class, const StringName &p_method, const Vector &p_values); static Vector get_method_error_return_values(const StringName &p_class, const StringName &p_method); static Variant class_get_default_property_value(const StringName &p_class, const StringName &p_property, bool *r_valid = nullptr); @@ -506,6 +513,9 @@ class ClassDB { #define BIND_CONSTANT(m_constant) \ ::ClassDB::bind_integer_constant(get_class_static(), StringName(), #m_constant, m_constant); +#define BIND_STRUCT(m_struct) \ + ::ClassDB::bind_struct(get_class_static(), m_struct::Layout::get_struct_info()); + #ifdef DEBUG_METHODS_ENABLED _FORCE_INLINE_ void errarray_add_str(Vector &arr) { diff --git a/core/object/method_info.cpp b/core/object/method_info.cpp new file mode 100644 index 000000000000..e79f937ea868 --- /dev/null +++ b/core/object/method_info.cpp @@ -0,0 +1,99 @@ +/**************************************************************************/ +/* method_info.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "method_info.h" +#include "core/variant/struct.h" +#include "core/variant/typed_array.h" + +PropertyInfo MethodInfo::return_val::from_variant(const Variant &p_variant) { + return PropertyInfo(Struct(p_variant)); +} + +Variant MethodInfo::return_val::to_variant(const PropertyInfo &p_value) { + return Struct(p_value); +} + +List MethodInfo::arguments::from_variant(const Variant &p_variant) { + return (List)TypedArray>(p_variant); +} + +Variant MethodInfo::arguments::to_variant(const List &p_value) { + return TypedArray>(&p_value); +} + +MethodInfo::operator Dictionary() const { + Dictionary d; + d["name"] = name; + d["args"] = convert_property_list(&arguments); + Array da; + for (int i = 0; i < default_arguments.size(); i++) { + da.push_back(default_arguments[i]); + } + d["default_args"] = da; + d["flags"] = flags; + d["id"] = id; + Dictionary r = return_val; + d["return"] = r; + return d; +} + +MethodInfo MethodInfo::from_dict(const Dictionary &p_dict) { + MethodInfo mi; + + if (p_dict.has("name")) { + mi.name = p_dict["name"]; + } + Array args; + if (p_dict.has("args")) { + args = p_dict["args"]; + } + + for (const Variant &arg : args) { + Dictionary d = arg; + mi.arguments.push_back(PropertyInfo::from_dict(d)); + } + Array defargs; + if (p_dict.has("default_args")) { + defargs = p_dict["default_args"]; + } + for (const Variant &defarg : defargs) { + mi.default_arguments.push_back(defarg); + } + + if (p_dict.has("return")) { + mi.return_val = PropertyInfo::from_dict(p_dict["return"]); + } + + if (p_dict.has("flags")) { + mi.flags = p_dict["flags"]; + } + + return mi; +} diff --git a/core/object/method_info.h b/core/object/method_info.h new file mode 100644 index 000000000000..d2b2668d1c61 --- /dev/null +++ b/core/object/method_info.h @@ -0,0 +1,137 @@ +/**************************************************************************/ +/* method_info.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef METHOD_INFO_H +#define METHOD_INFO_H + +#include "core/object/property_info.h" +#include "core/variant/variant.h" + +enum MethodFlags { + METHOD_FLAG_NORMAL = 1, + METHOD_FLAG_EDITOR = 2, + METHOD_FLAG_CONST = 4, + METHOD_FLAG_VIRTUAL = 8, + METHOD_FLAG_VARARG = 16, + METHOD_FLAG_STATIC = 32, + METHOD_FLAG_OBJECT_CORE = 64, + METHOD_FLAG_VIRTUAL_REQUIRED = 128, + METHOD_FLAGS_DEFAULT = METHOD_FLAG_NORMAL, +}; + +struct MethodInfo { + STRUCT_DECLARE(MethodInfo); + STRUCT_MEMBER_PRIMITIVE(String, name, String()); + STRUCT_MEMBER_PRIMITIVE_FROM_TO_ALIAS(List, arguments, "args", List()); + STRUCT_MEMBER_PRIMITIVE_ALIAS(Vector, default_arguments, "default_args", Vector()); + STRUCT_MEMBER_PRIMITIVE(uint32_t, flags, METHOD_FLAGS_DEFAULT); + STRUCT_MEMBER_PRIMITIVE(int, id, 0); + STRUCT_MEMBER_STRUCT_FROM_TO_ALIAS(PropertyInfo, return_val, "return", PropertyInfo()); + + STRUCT_MEMBER_PRIMITIVE(int, return_val_metadata, 0); + STRUCT_MEMBER_PRIMITIVE(Vector, arguments_metadata, Vector()); + STRUCT_LAYOUT_OWNER(Object, MethodInfo, struct name, struct arguments, struct default_arguments, struct flags, struct id, struct return_val, struct return_val_metadata, struct arguments_metadata); + + int get_argument_meta(int p_arg) const { + ERR_FAIL_COND_V(p_arg < -1 || p_arg > arguments.size(), 0); + if (p_arg == -1) { + return return_val_metadata; + } + return arguments_metadata.size() > p_arg ? arguments_metadata[p_arg] : 0; + } + + inline bool operator==(const MethodInfo &p_method) const { return id == p_method.id; } + inline bool operator<(const MethodInfo &p_method) const { return id == p_method.id ? (name < p_method.name) : (id < p_method.id); } + + operator Dictionary() const; + + static MethodInfo from_dict(const Dictionary &p_dict); + + MethodInfo() {} + + explicit MethodInfo(const GDExtensionMethodInfo &pinfo) : + name(*reinterpret_cast(pinfo.name)) { + for (uint32_t j = 0; j < pinfo.argument_count; j++) { + arguments.push_back(PropertyInfo(pinfo.arguments[j])); + } + const Variant *def_values = (const Variant *)pinfo.default_arguments; + for (uint32_t j = 0; j < pinfo.default_argument_count; j++) { + default_arguments.push_back(def_values[j]); + } + flags = pinfo.flags; + id = pinfo.id; + return_val = PropertyInfo(pinfo.return_value); + } + + void _push_params(const PropertyInfo &p_param) { + arguments.push_back(p_param); + } + + template + void _push_params(const PropertyInfo &p_param, VarArgs... p_params) { + arguments.push_back(p_param); + _push_params(p_params...); + } + + MethodInfo(const String &p_name) { name = p_name; } + + template + MethodInfo(const String &p_name, VarArgs... p_params) { + name = p_name; + _push_params(p_params...); + } + + MethodInfo(Variant::Type ret) { return_val.type = ret; } + MethodInfo(Variant::Type ret, const String &p_name) { + return_val.type = ret; + name = p_name; + } + + template + MethodInfo(Variant::Type ret, const String &p_name, VarArgs... p_params) { + name = p_name; + return_val.type = ret; + _push_params(p_params...); + } + + MethodInfo(const PropertyInfo &p_ret, const String &p_name) { + return_val = p_ret; + name = p_name; + } + + template + MethodInfo(const PropertyInfo &p_ret, const String &p_name, VarArgs... p_params) { + return_val = p_ret; + name = p_name; + _push_params(p_params...); + } +}; + +#endif // METHOD_INFO_H diff --git a/core/object/object.cpp b/core/object/object.cpp index ef1ca8132cbd..e679521b990d 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -39,6 +39,7 @@ #include "core/string/print_string.h" #include "core/string/translation_server.h" #include "core/templates/local_vector.h" +#include "core/variant/struct.h" #include "core/variant/typed_array.h" #ifdef DEBUG_ENABLED @@ -66,106 +67,6 @@ struct _ObjectDebugLock { #endif -PropertyInfo::operator Dictionary() const { - Dictionary d; - d["name"] = name; - d["class_name"] = class_name; - d["type"] = type; - d["hint"] = hint; - d["hint_string"] = hint_string; - d["usage"] = usage; - return d; -} - -PropertyInfo PropertyInfo::from_dict(const Dictionary &p_dict) { - PropertyInfo pi; - - if (p_dict.has("type")) { - pi.type = Variant::Type(int(p_dict["type"])); - } - - if (p_dict.has("name")) { - pi.name = p_dict["name"]; - } - - if (p_dict.has("class_name")) { - pi.class_name = p_dict["class_name"]; - } - - if (p_dict.has("hint")) { - pi.hint = PropertyHint(int(p_dict["hint"])); - } - - if (p_dict.has("hint_string")) { - pi.hint_string = p_dict["hint_string"]; - } - - if (p_dict.has("usage")) { - pi.usage = p_dict["usage"]; - } - - return pi; -} - -TypedArray convert_property_list(const List *p_list) { - TypedArray va; - for (const List::Element *E = p_list->front(); E; E = E->next()) { - va.push_back(Dictionary(E->get())); - } - - return va; -} - -MethodInfo::operator Dictionary() const { - Dictionary d; - d["name"] = name; - d["args"] = convert_property_list(&arguments); - Array da; - for (int i = 0; i < default_arguments.size(); i++) { - da.push_back(default_arguments[i]); - } - d["default_args"] = da; - d["flags"] = flags; - d["id"] = id; - Dictionary r = return_val; - d["return"] = r; - return d; -} - -MethodInfo MethodInfo::from_dict(const Dictionary &p_dict) { - MethodInfo mi; - - if (p_dict.has("name")) { - mi.name = p_dict["name"]; - } - Array args; - if (p_dict.has("args")) { - args = p_dict["args"]; - } - - for (const Variant &arg : args) { - Dictionary d = arg; - mi.arguments.push_back(PropertyInfo::from_dict(d)); - } - Array defargs; - if (p_dict.has("default_args")) { - defargs = p_dict["default_args"]; - } - for (const Variant &defarg : defargs) { - mi.default_arguments.push_back(defarg); - } - - if (p_dict.has("return")) { - mi.return_val = PropertyInfo::from_dict(p_dict["return"]); - } - - if (p_dict.has("flags")) { - mi.flags = p_dict["flags"]; - } - - return mi; -} - Object::Connection::operator Variant() const { Dictionary d; d["signal"] = signal; @@ -1039,6 +940,12 @@ TypedArray Object::_get_property_list_bind() const { return convert_property_list(&lpi); } +//TypedArray> Object::_get_property_list_as_structs_bind() const { +// List lpi; +// get_property_list(&lpi); +// return TypedArray>(&lpi); +//} + TypedArray Object::_get_method_list_bind() const { List ml; get_method_list(&ml); @@ -1053,6 +960,12 @@ TypedArray Object::_get_method_list_bind() const { return ret; } +//TypedArray> Object::_get_method_list_as_structs_bind() const { +// List ml; +// get_method_list(&ml); +// return TypedArray>(&ml); +//} + TypedArray Object::_get_meta_list_bind() const { TypedArray _metaret; @@ -1253,6 +1166,10 @@ void Object::_add_user_signal(const String &p_name, const Array &p_args) { } } +//void Object::_add_user_signal_as_struct(const Struct &p_signal) { +// add_user_signal(MethodInfo(p_signal)); +//} + TypedArray Object::_get_signal_list() const { List signal_list; get_signal_list(&signal_list); @@ -1265,6 +1182,12 @@ TypedArray Object::_get_signal_list() const { return ret; } +//TypedArray> Object::_get_signal_list_as_structs() const { +// List signal_list; +// get_signal_list(&signal_list); +// return TypedArray>(&signal_list); +//} + TypedArray Object::_get_signal_connection_list(const StringName &p_signal) const { List conns; get_all_signal_connections(&conns); @@ -1280,6 +1203,12 @@ TypedArray Object::_get_signal_connection_list(const StringName &p_s return ret; } +//TypedArray> Object::_get_signal_connection_list_as_structs(const StringName &p_signal) const { +// List conns; +// get_all_signal_connections(&conns); +// return TypedArray>(&conns); +//} + TypedArray Object::_get_incoming_connections() const { TypedArray ret; for (const Object::Connection &connection : connections) { @@ -1289,6 +1218,10 @@ TypedArray Object::_get_incoming_connections() const { return ret; } +//TypedArray> Object::_get_incoming_connections_as_structs() const { +// return TypedArray>(&connections); +//} + bool Object::has_signal(const StringName &p_name) const { if (!script.is_null()) { Ref