Skip to content

Commit 147ccfe

Browse files
committed
Merge pull request godotengine#96329 from Delsin-Yu/dotnet-replace-array-with-ros-in-binding-apis
[.NET] Generate `ReadOnlySpan<T>` Overloads for GodotSharp APIs
2 parents 16dfaa5 + d4695e8 commit 147ccfe

File tree

3 files changed

+120
-20
lines changed

3 files changed

+120
-20
lines changed

modules/mono/editor/bindings_generator.cpp

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2348,9 +2348,17 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
23482348

23492349
int method_bind_count = 0;
23502350
for (const MethodInterface &imethod : itype.methods) {
2351-
Error method_err = _generate_cs_method(itype, imethod, method_bind_count, output);
2351+
Error method_err = _generate_cs_method(itype, imethod, method_bind_count, output, false);
23522352
ERR_FAIL_COND_V_MSG(method_err != OK, method_err,
23532353
"Failed to generate method '" + imethod.name + "' for class '" + itype.name + "'.");
2354+
if (imethod.is_internal) {
2355+
// No need to generate span overloads for internal methods.
2356+
continue;
2357+
}
2358+
2359+
method_err = _generate_cs_method(itype, imethod, method_bind_count, output, true);
2360+
ERR_FAIL_COND_V_MSG(method_err != OK, method_err,
2361+
"Failed to generate span overload method '" + imethod.name + "' for class '" + itype.name + "'.");
23542362
}
23552363

23562364
// Signals
@@ -2776,7 +2784,7 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
27762784
return OK;
27772785
}
27782786

2779-
Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::MethodInterface &p_imethod, int &p_method_bind_count, StringBuilder &p_output) {
2787+
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) {
27802788
const TypeInterface *return_type = _get_type_or_singleton_or_null(p_imethod.return_type);
27812789
ERR_FAIL_NULL_V_MSG(return_type, ERR_BUG, "Return type '" + p_imethod.return_type.cname + "' was not found.");
27822790

@@ -2789,6 +2797,35 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
27892797
"' from the editor API. Core API cannot have dependencies on the editor API.");
27902798
}
27912799

2800+
if (p_imethod.is_virtual && p_use_span) {
2801+
return OK;
2802+
}
2803+
2804+
bool has_span_argument = false;
2805+
2806+
if (p_use_span) {
2807+
if (p_imethod.is_vararg) {
2808+
has_span_argument = true;
2809+
} else {
2810+
for (const ArgumentInterface &iarg : p_imethod.arguments) {
2811+
const TypeInterface *arg_type = _get_type_or_singleton_or_null(iarg.type);
2812+
ERR_FAIL_NULL_V_MSG(arg_type, ERR_BUG, "Argument type '" + iarg.type.cname + "' was not found.");
2813+
2814+
if (arg_type->is_span_compatible) {
2815+
has_span_argument = true;
2816+
break;
2817+
}
2818+
}
2819+
}
2820+
2821+
if (has_span_argument) {
2822+
// Span overloads use the same method bind as the array overloads.
2823+
// Since both overloads are generated one after the other, we can decrease the count here
2824+
// to ensure the span overload uses the same method bind.
2825+
p_method_bind_count--;
2826+
}
2827+
}
2828+
27922829
String method_bind_field = CS_STATIC_FIELD_METHOD_BIND_PREFIX + itos(p_method_bind_count);
27932830

27942831
String arguments_sig;
@@ -2835,6 +2872,8 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
28352872

28362873
String arg_cs_type = arg_type->cs_type + _get_generic_type_parameters(*arg_type, iarg.type.generic_type_parameters);
28372874

2875+
bool use_span_for_arg = p_use_span && arg_type->is_span_compatible;
2876+
28382877
// Add the current arguments to the signature
28392878
// If the argument has a default value which is not a constant, we will make it Nullable
28402879
{
@@ -2846,7 +2885,11 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
28462885
arguments_sig += "Nullable<";
28472886
}
28482887

2849-
arguments_sig += arg_cs_type;
2888+
if (use_span_for_arg) {
2889+
arguments_sig += arg_type->c_type_in;
2890+
} else {
2891+
arguments_sig += arg_cs_type;
2892+
}
28502893

28512894
if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL) {
28522895
arguments_sig += "> ";
@@ -2856,7 +2899,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
28562899

28572900
arguments_sig += iarg.name;
28582901

2859-
if (!p_imethod.is_compat && iarg.default_argument.size()) {
2902+
if (!p_use_span && !p_imethod.is_compat && iarg.default_argument.size()) {
28602903
if (iarg.def_param_mode != ArgumentInterface::CONSTANT) {
28612904
arguments_sig += " = null";
28622905
} else {
@@ -2867,7 +2910,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
28672910

28682911
icall_params += ", ";
28692912

2870-
if (iarg.default_argument.size() && iarg.def_param_mode != ArgumentInterface::CONSTANT) {
2913+
if (iarg.default_argument.size() && iarg.def_param_mode != ArgumentInterface::CONSTANT && !use_span_for_arg) {
28712914
// The default value of an argument must be constant. Otherwise we make it Nullable and do the following:
28722915
// Type arg_in = arg.HasValue ? arg.Value : <non-const default value>;
28732916
String arg_or_defval_local = iarg.name;
@@ -2927,14 +2970,18 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
29272970
cs_in_expr_is_unsafe |= arg_type->cs_in_expr_is_unsafe;
29282971
}
29292972

2973+
if (p_use_span && !has_span_argument) {
2974+
return OK;
2975+
}
2976+
29302977
// Collect caller name for MethodBind
29312978
if (p_imethod.is_vararg) {
29322979
icall_params += ", (godot_string_name)MethodName." + p_imethod.proxy_name + ".NativeValue";
29332980
}
29342981

29352982
// Generate method
29362983
{
2937-
if (!p_imethod.is_virtual && !p_imethod.requires_object_call) {
2984+
if (!p_imethod.is_virtual && !p_imethod.requires_object_call && !p_use_span) {
29382985
p_output << MEMBER_BEGIN "[DebuggerBrowsable(DebuggerBrowsableState.Never)]\n"
29392986
<< INDENT1 "private static readonly IntPtr " << method_bind_field << " = ";
29402987

@@ -4734,13 +4781,14 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
47344781
itype = TypeInterface();
47354782
itype.name = "VarArg";
47364783
itype.cname = itype.name;
4737-
itype.proxy_name = "Variant[]";
4784+
itype.proxy_name = "ReadOnlySpan<Variant>";
47384785
itype.cs_type = "params Variant[]";
4739-
itype.cs_in_expr = "%0 ?? Array.Empty<Variant>()";
4786+
itype.cs_in_expr = "%0";
47404787
// c_type, c_in and c_arg_in are hard-coded in the generator.
47414788
// c_out and c_type_out are not applicable to VarArg.
47424789
itype.c_arg_in = "&%s_in";
4743-
itype.c_type_in = "Variant[]";
4790+
itype.c_type_in = "ReadOnlySpan<Variant>";
4791+
itype.is_span_compatible = true;
47444792
builtin_types.insert(itype.cname, itype);
47454793

47464794
#define INSERT_ARRAY_FULL(m_name, m_type, m_managed_type, m_proxy_t) \
@@ -4754,9 +4802,10 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
47544802
itype.c_out = "%5return " C_METHOD_MONOARRAY_FROM(m_type) "(%1);\n"; \
47554803
itype.c_arg_in = "&%s_in"; \
47564804
itype.c_type = #m_managed_type; \
4757-
itype.c_type_in = itype.proxy_name; \
4805+
itype.c_type_in = "ReadOnlySpan<" #m_proxy_t ">"; \
47584806
itype.c_type_out = itype.proxy_name; \
47594807
itype.c_type_is_disposable_struct = true; \
4808+
itype.is_span_compatible = true; \
47604809
builtin_types.insert(itype.name, itype); \
47614810
}
47624811

modules/mono/editor/bindings_generator.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ class BindingsGenerator {
265265
bool is_singleton = false;
266266
bool is_singleton_instance = false;
267267
bool is_ref_counted = false;
268+
bool is_span_compatible = false;
268269

269270
/**
270271
* Class is a singleton, but can't be declared as a static class as that would
@@ -840,7 +841,7 @@ class BindingsGenerator {
840841
Error _generate_cs_type(const TypeInterface &itype, const String &p_output_file);
841842

842843
Error _generate_cs_property(const TypeInterface &p_itype, const PropertyInterface &p_iprop, StringBuilder &p_output);
843-
Error _generate_cs_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, int &p_method_bind_count, StringBuilder &p_output);
844+
Error _generate_cs_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, int &p_method_bind_count, StringBuilder &p_output, bool p_use_span);
844845
Error _generate_cs_signal(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::SignalInterface &p_isignal, StringBuilder &p_output);
845846

846847
Error _generate_cs_native_calls(const InternalCall &p_icall, StringBuilder &r_output);

modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs

Lines changed: 59 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,12 @@ public static unsafe byte[] ConvertNativePackedByteArrayToSystemArray(in godot_p
394394
return array;
395395
}
396396

397-
public static unsafe godot_packed_byte_array ConvertSystemArrayToNativePackedByteArray(Span<byte> p_array)
397+
public static godot_packed_byte_array ConvertSystemArrayToNativePackedByteArray(Span<byte> p_array)
398+
{
399+
return ConvertSystemArrayToNativePackedByteArray((ReadOnlySpan<byte>)p_array);
400+
}
401+
402+
public static unsafe godot_packed_byte_array ConvertSystemArrayToNativePackedByteArray(ReadOnlySpan<byte> p_array)
398403
{
399404
if (p_array.IsEmpty)
400405
return new godot_packed_byte_array();
@@ -417,7 +422,12 @@ public static unsafe int[] ConvertNativePackedInt32ArrayToSystemArray(godot_pack
417422
return array;
418423
}
419424

420-
public static unsafe godot_packed_int32_array ConvertSystemArrayToNativePackedInt32Array(Span<int> p_array)
425+
public static godot_packed_int32_array ConvertSystemArrayToNativePackedInt32Array(Span<int> p_array)
426+
{
427+
return ConvertSystemArrayToNativePackedInt32Array((ReadOnlySpan<int>)p_array);
428+
}
429+
430+
public static unsafe godot_packed_int32_array ConvertSystemArrayToNativePackedInt32Array(ReadOnlySpan<int> p_array)
421431
{
422432
if (p_array.IsEmpty)
423433
return new godot_packed_int32_array();
@@ -440,7 +450,12 @@ public static unsafe long[] ConvertNativePackedInt64ArrayToSystemArray(godot_pac
440450
return array;
441451
}
442452

443-
public static unsafe godot_packed_int64_array ConvertSystemArrayToNativePackedInt64Array(Span<long> p_array)
453+
public static godot_packed_int64_array ConvertSystemArrayToNativePackedInt64Array(Span<long> p_array)
454+
{
455+
return ConvertSystemArrayToNativePackedInt64Array((ReadOnlySpan<long>)p_array);
456+
}
457+
458+
public static unsafe godot_packed_int64_array ConvertSystemArrayToNativePackedInt64Array(ReadOnlySpan<long> p_array)
444459
{
445460
if (p_array.IsEmpty)
446461
return new godot_packed_int64_array();
@@ -463,8 +478,13 @@ public static unsafe float[] ConvertNativePackedFloat32ArrayToSystemArray(godot_
463478
return array;
464479
}
465480

481+
public static godot_packed_float32_array ConvertSystemArrayToNativePackedFloat32Array(Span<float> p_array)
482+
{
483+
return ConvertSystemArrayToNativePackedFloat32Array((ReadOnlySpan<float>)p_array);
484+
}
485+
466486
public static unsafe godot_packed_float32_array ConvertSystemArrayToNativePackedFloat32Array(
467-
Span<float> p_array)
487+
ReadOnlySpan<float> p_array)
468488
{
469489
if (p_array.IsEmpty)
470490
return new godot_packed_float32_array();
@@ -487,8 +507,13 @@ public static unsafe double[] ConvertNativePackedFloat64ArrayToSystemArray(godot
487507
return array;
488508
}
489509

510+
public static godot_packed_float64_array ConvertSystemArrayToNativePackedFloat64Array(Span<double> p_array)
511+
{
512+
return ConvertSystemArrayToNativePackedFloat64Array((ReadOnlySpan<double>)p_array);
513+
}
514+
490515
public static unsafe godot_packed_float64_array ConvertSystemArrayToNativePackedFloat64Array(
491-
Span<double> p_array)
516+
ReadOnlySpan<double> p_array)
492517
{
493518
if (p_array.IsEmpty)
494519
return new godot_packed_float64_array();
@@ -511,6 +536,11 @@ public static unsafe string[] ConvertNativePackedStringArrayToSystemArray(godot_
511536
}
512537

513538
public static godot_packed_string_array ConvertSystemArrayToNativePackedStringArray(Span<string> p_array)
539+
{
540+
return ConvertSystemArrayToNativePackedStringArray((ReadOnlySpan<string>)p_array);
541+
}
542+
543+
public static godot_packed_string_array ConvertSystemArrayToNativePackedStringArray(ReadOnlySpan<string> p_array)
514544
{
515545
godot_packed_string_array dest = new godot_packed_string_array();
516546

@@ -544,8 +574,13 @@ public static unsafe Vector2[] ConvertNativePackedVector2ArrayToSystemArray(godo
544574
return array;
545575
}
546576

577+
public static godot_packed_vector2_array ConvertSystemArrayToNativePackedVector2Array(Span<Vector2> p_array)
578+
{
579+
return ConvertSystemArrayToNativePackedVector2Array((ReadOnlySpan<Vector2>)p_array);
580+
}
581+
547582
public static unsafe godot_packed_vector2_array ConvertSystemArrayToNativePackedVector2Array(
548-
Span<Vector2> p_array)
583+
ReadOnlySpan<Vector2> p_array)
549584
{
550585
if (p_array.IsEmpty)
551586
return new godot_packed_vector2_array();
@@ -568,8 +603,13 @@ public static unsafe Vector3[] ConvertNativePackedVector3ArrayToSystemArray(godo
568603
return array;
569604
}
570605

606+
public static godot_packed_vector3_array ConvertSystemArrayToNativePackedVector3Array(Span<Vector3> p_array)
607+
{
608+
return ConvertSystemArrayToNativePackedVector3Array((ReadOnlySpan<Vector3>)p_array);
609+
}
610+
571611
public static unsafe godot_packed_vector3_array ConvertSystemArrayToNativePackedVector3Array(
572-
Span<Vector3> p_array)
612+
ReadOnlySpan<Vector3> p_array)
573613
{
574614
if (p_array.IsEmpty)
575615
return new godot_packed_vector3_array();
@@ -592,8 +632,13 @@ public static unsafe Vector4[] ConvertNativePackedVector4ArrayToSystemArray(godo
592632
return array;
593633
}
594634

635+
public static godot_packed_vector4_array ConvertSystemArrayToNativePackedVector4Array(Span<Vector4> p_array)
636+
{
637+
return ConvertSystemArrayToNativePackedVector4Array((ReadOnlySpan<Vector4>)p_array);
638+
}
639+
595640
public static unsafe godot_packed_vector4_array ConvertSystemArrayToNativePackedVector4Array(
596-
Span<Vector4> p_array)
641+
ReadOnlySpan<Vector4> p_array)
597642
{
598643
if (p_array.IsEmpty)
599644
return new godot_packed_vector4_array();
@@ -616,7 +661,12 @@ public static unsafe Color[] ConvertNativePackedColorArrayToSystemArray(godot_pa
616661
return array;
617662
}
618663

619-
public static unsafe godot_packed_color_array ConvertSystemArrayToNativePackedColorArray(Span<Color> p_array)
664+
public static godot_packed_color_array ConvertSystemArrayToNativePackedColorArray(Span<Color> p_array)
665+
{
666+
return ConvertSystemArrayToNativePackedColorArray((ReadOnlySpan<Color>)p_array);
667+
}
668+
669+
public static unsafe godot_packed_color_array ConvertSystemArrayToNativePackedColorArray(ReadOnlySpan<Color> p_array)
620670
{
621671
if (p_array.IsEmpty)
622672
return new godot_packed_color_array();

0 commit comments

Comments
 (0)