diff options
author | Thaddeus Crews <repiteo@outlook.com> | 2024-10-10 18:13:18 -0500 |
---|---|---|
committer | Thaddeus Crews <repiteo@outlook.com> | 2024-10-10 18:13:18 -0500 |
commit | 147ccfeb4ecc01b0cc497b4bc54e0e80607198ff (patch) | |
tree | b587fbfc99dbec029019669f06d1a2f660dad3b7 | |
parent | 16dfaa5e8011d32690f733a5629e0aebe4da5021 (diff) | |
parent | d4695e84a4a5acf4644bf6adee58e3a87c9a511c (diff) | |
download | redot-engine-147ccfeb4ecc01b0cc497b4bc54e0e80607198ff.tar.gz |
Merge pull request #96329 from Delsin-Yu/dotnet-replace-array-with-ros-in-binding-apis
[.NET] Generate `ReadOnlySpan<T>` Overloads for GodotSharp APIs
-rw-r--r-- | modules/mono/editor/bindings_generator.cpp | 69 | ||||
-rw-r--r-- | modules/mono/editor/bindings_generator.h | 3 | ||||
-rw-r--r-- | modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs | 68 |
3 files changed, 120 insertions, 20 deletions
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 89655e0b56..946e997c1b 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -2348,9 +2348,17 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str int method_bind_count = 0; for (const MethodInterface &imethod : itype.methods) { - Error method_err = _generate_cs_method(itype, imethod, method_bind_count, output); + Error method_err = _generate_cs_method(itype, imethod, method_bind_count, output, false); ERR_FAIL_COND_V_MSG(method_err != OK, method_err, "Failed to generate method '" + imethod.name + "' for class '" + itype.name + "'."); + if (imethod.is_internal) { + // No need to generate span overloads for internal methods. + continue; + } + + method_err = _generate_cs_method(itype, imethod, method_bind_count, output, true); + ERR_FAIL_COND_V_MSG(method_err != OK, method_err, + "Failed to generate span overload method '" + imethod.name + "' for class '" + itype.name + "'."); } // Signals @@ -2776,7 +2784,7 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte return OK; } -Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::MethodInterface &p_imethod, int &p_method_bind_count, StringBuilder &p_output) { +Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::MethodInterface &p_imethod, int &p_method_bind_count, StringBuilder &p_output, bool p_use_span) { const TypeInterface *return_type = _get_type_or_singleton_or_null(p_imethod.return_type); ERR_FAIL_NULL_V_MSG(return_type, ERR_BUG, "Return type '" + p_imethod.return_type.cname + "' was not found."); @@ -2789,6 +2797,35 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf "' from the editor API. Core API cannot have dependencies on the editor API."); } + if (p_imethod.is_virtual && p_use_span) { + return OK; + } + + bool has_span_argument = false; + + if (p_use_span) { + if (p_imethod.is_vararg) { + has_span_argument = true; + } else { + for (const ArgumentInterface &iarg : p_imethod.arguments) { + const TypeInterface *arg_type = _get_type_or_singleton_or_null(iarg.type); + ERR_FAIL_NULL_V_MSG(arg_type, ERR_BUG, "Argument type '" + iarg.type.cname + "' was not found."); + + if (arg_type->is_span_compatible) { + has_span_argument = true; + break; + } + } + } + + if (has_span_argument) { + // Span overloads use the same method bind as the array overloads. + // Since both overloads are generated one after the other, we can decrease the count here + // to ensure the span overload uses the same method bind. + p_method_bind_count--; + } + } + String method_bind_field = CS_STATIC_FIELD_METHOD_BIND_PREFIX + itos(p_method_bind_count); String arguments_sig; @@ -2835,6 +2872,8 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf String arg_cs_type = arg_type->cs_type + _get_generic_type_parameters(*arg_type, iarg.type.generic_type_parameters); + bool use_span_for_arg = p_use_span && arg_type->is_span_compatible; + // Add the current arguments to the signature // If the argument has a default value which is not a constant, we will make it Nullable { @@ -2846,7 +2885,11 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf arguments_sig += "Nullable<"; } - arguments_sig += arg_cs_type; + if (use_span_for_arg) { + arguments_sig += arg_type->c_type_in; + } else { + arguments_sig += arg_cs_type; + } if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL) { arguments_sig += "> "; @@ -2856,7 +2899,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf arguments_sig += iarg.name; - if (!p_imethod.is_compat && iarg.default_argument.size()) { + if (!p_use_span && !p_imethod.is_compat && iarg.default_argument.size()) { if (iarg.def_param_mode != ArgumentInterface::CONSTANT) { arguments_sig += " = null"; } else { @@ -2867,7 +2910,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf icall_params += ", "; - if (iarg.default_argument.size() && iarg.def_param_mode != ArgumentInterface::CONSTANT) { + if (iarg.default_argument.size() && iarg.def_param_mode != ArgumentInterface::CONSTANT && !use_span_for_arg) { // The default value of an argument must be constant. Otherwise we make it Nullable and do the following: // Type arg_in = arg.HasValue ? arg.Value : <non-const default value>; String arg_or_defval_local = iarg.name; @@ -2927,6 +2970,10 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf cs_in_expr_is_unsafe |= arg_type->cs_in_expr_is_unsafe; } + if (p_use_span && !has_span_argument) { + return OK; + } + // Collect caller name for MethodBind if (p_imethod.is_vararg) { icall_params += ", (godot_string_name)MethodName." + p_imethod.proxy_name + ".NativeValue"; @@ -2934,7 +2981,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf // Generate method { - if (!p_imethod.is_virtual && !p_imethod.requires_object_call) { + if (!p_imethod.is_virtual && !p_imethod.requires_object_call && !p_use_span) { p_output << MEMBER_BEGIN "[DebuggerBrowsable(DebuggerBrowsableState.Never)]\n" << INDENT1 "private static readonly IntPtr " << method_bind_field << " = "; @@ -4734,13 +4781,14 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype = TypeInterface(); itype.name = "VarArg"; itype.cname = itype.name; - itype.proxy_name = "Variant[]"; + itype.proxy_name = "ReadOnlySpan<Variant>"; itype.cs_type = "params Variant[]"; - itype.cs_in_expr = "%0 ?? Array.Empty<Variant>()"; + itype.cs_in_expr = "%0"; // c_type, c_in and c_arg_in are hard-coded in the generator. // c_out and c_type_out are not applicable to VarArg. itype.c_arg_in = "&%s_in"; - itype.c_type_in = "Variant[]"; + itype.c_type_in = "ReadOnlySpan<Variant>"; + itype.is_span_compatible = true; builtin_types.insert(itype.cname, itype); #define INSERT_ARRAY_FULL(m_name, m_type, m_managed_type, m_proxy_t) \ @@ -4754,9 +4802,10 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.c_out = "%5return " C_METHOD_MONOARRAY_FROM(m_type) "(%1);\n"; \ itype.c_arg_in = "&%s_in"; \ itype.c_type = #m_managed_type; \ - itype.c_type_in = itype.proxy_name; \ + itype.c_type_in = "ReadOnlySpan<" #m_proxy_t ">"; \ itype.c_type_out = itype.proxy_name; \ itype.c_type_is_disposable_struct = true; \ + itype.is_span_compatible = true; \ builtin_types.insert(itype.name, itype); \ } diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index 556d287af4..1670aca4b3 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -265,6 +265,7 @@ class BindingsGenerator { bool is_singleton = false; bool is_singleton_instance = false; bool is_ref_counted = false; + bool is_span_compatible = false; /** * Class is a singleton, but can't be declared as a static class as that would @@ -840,7 +841,7 @@ class BindingsGenerator { Error _generate_cs_type(const TypeInterface &itype, const String &p_output_file); Error _generate_cs_property(const TypeInterface &p_itype, const PropertyInterface &p_iprop, StringBuilder &p_output); - Error _generate_cs_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, int &p_method_bind_count, StringBuilder &p_output); + Error _generate_cs_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, int &p_method_bind_count, StringBuilder &p_output, bool p_use_span); Error _generate_cs_signal(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::SignalInterface &p_isignal, StringBuilder &p_output); Error _generate_cs_native_calls(const InternalCall &p_icall, StringBuilder &r_output); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs index 15b7ce7c73..fc68b11932 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs @@ -394,7 +394,12 @@ namespace Godot.NativeInterop return array; } - public static unsafe godot_packed_byte_array ConvertSystemArrayToNativePackedByteArray(Span<byte> p_array) + public static godot_packed_byte_array ConvertSystemArrayToNativePackedByteArray(Span<byte> p_array) + { + return ConvertSystemArrayToNativePackedByteArray((ReadOnlySpan<byte>)p_array); + } + + public static unsafe godot_packed_byte_array ConvertSystemArrayToNativePackedByteArray(ReadOnlySpan<byte> p_array) { if (p_array.IsEmpty) return new godot_packed_byte_array(); @@ -417,7 +422,12 @@ namespace Godot.NativeInterop return array; } - public static unsafe godot_packed_int32_array ConvertSystemArrayToNativePackedInt32Array(Span<int> p_array) + public static godot_packed_int32_array ConvertSystemArrayToNativePackedInt32Array(Span<int> p_array) + { + return ConvertSystemArrayToNativePackedInt32Array((ReadOnlySpan<int>)p_array); + } + + public static unsafe godot_packed_int32_array ConvertSystemArrayToNativePackedInt32Array(ReadOnlySpan<int> p_array) { if (p_array.IsEmpty) return new godot_packed_int32_array(); @@ -440,7 +450,12 @@ namespace Godot.NativeInterop return array; } - public static unsafe godot_packed_int64_array ConvertSystemArrayToNativePackedInt64Array(Span<long> p_array) + public static godot_packed_int64_array ConvertSystemArrayToNativePackedInt64Array(Span<long> p_array) + { + return ConvertSystemArrayToNativePackedInt64Array((ReadOnlySpan<long>)p_array); + } + + public static unsafe godot_packed_int64_array ConvertSystemArrayToNativePackedInt64Array(ReadOnlySpan<long> p_array) { if (p_array.IsEmpty) return new godot_packed_int64_array(); @@ -463,8 +478,13 @@ namespace Godot.NativeInterop return array; } + public static godot_packed_float32_array ConvertSystemArrayToNativePackedFloat32Array(Span<float> p_array) + { + return ConvertSystemArrayToNativePackedFloat32Array((ReadOnlySpan<float>)p_array); + } + public static unsafe godot_packed_float32_array ConvertSystemArrayToNativePackedFloat32Array( - Span<float> p_array) + ReadOnlySpan<float> p_array) { if (p_array.IsEmpty) return new godot_packed_float32_array(); @@ -487,8 +507,13 @@ namespace Godot.NativeInterop return array; } + public static godot_packed_float64_array ConvertSystemArrayToNativePackedFloat64Array(Span<double> p_array) + { + return ConvertSystemArrayToNativePackedFloat64Array((ReadOnlySpan<double>)p_array); + } + public static unsafe godot_packed_float64_array ConvertSystemArrayToNativePackedFloat64Array( - Span<double> p_array) + ReadOnlySpan<double> p_array) { if (p_array.IsEmpty) return new godot_packed_float64_array(); @@ -512,6 +537,11 @@ namespace Godot.NativeInterop public static godot_packed_string_array ConvertSystemArrayToNativePackedStringArray(Span<string> p_array) { + return ConvertSystemArrayToNativePackedStringArray((ReadOnlySpan<string>)p_array); + } + + public static godot_packed_string_array ConvertSystemArrayToNativePackedStringArray(ReadOnlySpan<string> p_array) + { godot_packed_string_array dest = new godot_packed_string_array(); if (p_array.IsEmpty) @@ -544,8 +574,13 @@ namespace Godot.NativeInterop return array; } + public static godot_packed_vector2_array ConvertSystemArrayToNativePackedVector2Array(Span<Vector2> p_array) + { + return ConvertSystemArrayToNativePackedVector2Array((ReadOnlySpan<Vector2>)p_array); + } + public static unsafe godot_packed_vector2_array ConvertSystemArrayToNativePackedVector2Array( - Span<Vector2> p_array) + ReadOnlySpan<Vector2> p_array) { if (p_array.IsEmpty) return new godot_packed_vector2_array(); @@ -568,8 +603,13 @@ namespace Godot.NativeInterop return array; } + public static godot_packed_vector3_array ConvertSystemArrayToNativePackedVector3Array(Span<Vector3> p_array) + { + return ConvertSystemArrayToNativePackedVector3Array((ReadOnlySpan<Vector3>)p_array); + } + public static unsafe godot_packed_vector3_array ConvertSystemArrayToNativePackedVector3Array( - Span<Vector3> p_array) + ReadOnlySpan<Vector3> p_array) { if (p_array.IsEmpty) return new godot_packed_vector3_array(); @@ -592,8 +632,13 @@ namespace Godot.NativeInterop return array; } + public static godot_packed_vector4_array ConvertSystemArrayToNativePackedVector4Array(Span<Vector4> p_array) + { + return ConvertSystemArrayToNativePackedVector4Array((ReadOnlySpan<Vector4>)p_array); + } + public static unsafe godot_packed_vector4_array ConvertSystemArrayToNativePackedVector4Array( - Span<Vector4> p_array) + ReadOnlySpan<Vector4> p_array) { if (p_array.IsEmpty) return new godot_packed_vector4_array(); @@ -616,7 +661,12 @@ namespace Godot.NativeInterop return array; } - public static unsafe godot_packed_color_array ConvertSystemArrayToNativePackedColorArray(Span<Color> p_array) + public static godot_packed_color_array ConvertSystemArrayToNativePackedColorArray(Span<Color> p_array) + { + return ConvertSystemArrayToNativePackedColorArray((ReadOnlySpan<Color>)p_array); + } + + public static unsafe godot_packed_color_array ConvertSystemArrayToNativePackedColorArray(ReadOnlySpan<Color> p_array) { if (p_array.IsEmpty) return new godot_packed_color_array(); |