diff options
14 files changed, 1009 insertions, 356 deletions
diff --git a/modules/mono/SdkPackageVersions.props b/modules/mono/SdkPackageVersions.props index 9947335b2f..50ef6d8d6c 100644 --- a/modules/mono/SdkPackageVersions.props +++ b/modules/mono/SdkPackageVersions.props @@ -2,6 +2,6 @@ <PropertyGroup> <PackageFloatingVersion_Godot>4.0.*-*</PackageFloatingVersion_Godot> <PackageVersion_Godot_NET_Sdk>4.0.0-dev7</PackageVersion_Godot_NET_Sdk> - <PackageVersion_Godot_SourceGenerators>4.0.0-dev7</PackageVersion_Godot_SourceGenerators> + <PackageVersion_Godot_SourceGenerators>4.0.0-dev8</PackageVersion_Godot_SourceGenerators> </PropertyGroup> </Project> diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs index 2179aeea88..4ac7274e41 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs @@ -190,6 +190,7 @@ namespace Godot.SourceGenerators if (method.IsGenericMethod) continue; + var retSymbol = method.ReturnType; var retType = method.ReturnsVoid ? null : MarshalUtils.ConvertManagedTypeToMarshalType(method.ReturnType, typeCache); @@ -212,7 +213,7 @@ namespace Godot.SourceGenerators continue; yield return new GodotMethodData(method, paramTypes, parameters - .Select(p => p.Type).ToImmutableArray(), retType); + .Select(p => p.Type).ToImmutableArray(), retType, retSymbol); } } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs index ff640a7a96..1a01ba2b9d 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs @@ -6,18 +6,20 @@ namespace Godot.SourceGenerators public struct GodotMethodData { public GodotMethodData(IMethodSymbol method, ImmutableArray<MarshalType> paramTypes, - ImmutableArray<ITypeSymbol> paramTypeSymbols, MarshalType? retType) + ImmutableArray<ITypeSymbol> paramTypeSymbols, MarshalType? retType, ITypeSymbol? retSymbol) { Method = method; ParamTypes = paramTypes; ParamTypeSymbols = paramTypeSymbols; RetType = retType; + RetSymbol = retSymbol; } public IMethodSymbol Method { get; } public ImmutableArray<MarshalType> ParamTypes { get; } public ImmutableArray<ITypeSymbol> ParamTypeSymbols { get; } public MarshalType? RetType { get; } + public ITypeSymbol? RetSymbol { get; } } public struct GodotPropertyData diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalType.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalType.cs index 1c4c19569e..3b7a50e7a6 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalType.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalType.cs @@ -46,14 +46,15 @@ namespace Godot.SourceGenerators ByteArray, Int32Array, Int64Array, - SingleArray, - DoubleArray, + Float32Array, + Float64Array, StringArray, Vector2Array, Vector3Array, ColorArray, GodotObjectOrDerivedArray, SystemObjectArray, + SystemArrayOfSupportedType, // Generics GodotGenericDictionary, diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs index 5a4badd66e..9dff404ede 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Text; using Microsoft.CodeAnalysis; namespace Godot.SourceGenerators @@ -11,7 +12,11 @@ namespace Godot.SourceGenerators public INamedTypeSymbol GodotObjectType { get; } public INamedTypeSymbol GodotGenericDictionary { get; } public INamedTypeSymbol GodotGenericArray { get; } + + // ReSharper disable once InconsistentNaming public INamedTypeSymbol IDictionary { get; } + + // ReSharper disable once InconsistentNaming public INamedTypeSymbol ICollection { get; } public INamedTypeSymbol GenericIDictionary { get; } public INamedTypeSymbol SystemGenericDictionary { get; } @@ -74,14 +79,15 @@ namespace Godot.SourceGenerators MarshalType.ByteArray => VariantType.PackedByteArray, MarshalType.Int32Array => VariantType.PackedInt32Array, MarshalType.Int64Array => VariantType.PackedInt64Array, - MarshalType.SingleArray => VariantType.PackedFloat32Array, - MarshalType.DoubleArray => VariantType.PackedFloat64Array, + MarshalType.Float32Array => VariantType.PackedFloat32Array, + MarshalType.Float64Array => VariantType.PackedFloat64Array, MarshalType.StringArray => VariantType.PackedStringArray, MarshalType.Vector2Array => VariantType.PackedVector2Array, MarshalType.Vector3Array => VariantType.PackedVector3Array, MarshalType.ColorArray => VariantType.PackedColorArray, MarshalType.GodotObjectOrDerivedArray => VariantType.Array, MarshalType.SystemObjectArray => VariantType.Array, + MarshalType.SystemArrayOfSupportedType => VariantType.Array, MarshalType.GodotGenericDictionary => VariantType.Dictionary, MarshalType.GodotGenericArray => VariantType.Array, MarshalType.SystemGenericDictionary => VariantType.Dictionary, @@ -187,9 +193,9 @@ namespace Godot.SourceGenerators case SpecialType.System_Int64: return MarshalType.Int64Array; case SpecialType.System_Single: - return MarshalType.SingleArray; + return MarshalType.Float32Array; case SpecialType.System_Double: - return MarshalType.DoubleArray; + return MarshalType.Float64Array; case SpecialType.System_String: return MarshalType.StringArray; case SpecialType.System_Object: @@ -209,12 +215,12 @@ namespace Godot.SourceGenerators case { Name: "Vector3" }: return MarshalType.Vector3Array; case { Name: "Color" }: - return MarshalType.ColorArray; + return MarshalType.ColorArray; } } if (ConvertManagedTypeToMarshalType(elementType, typeCache) != null) - return MarshalType.GodotArray; + return MarshalType.SystemArrayOfSupportedType; return null; } @@ -316,5 +322,292 @@ namespace Godot.SourceGenerators return null; } + + private static StringBuilder Append(this StringBuilder source, string a, string b, string c) + => source.Append(a).Append(b).Append(c); + + private static StringBuilder Append(this StringBuilder source, string a, string b, + string c, string d) + => source.Append(a).Append(b).Append(c).Append(d); + + private static StringBuilder Append(this StringBuilder source, string a, string b, + string c, string d, string e) + => source.Append(a).Append(b).Append(c).Append(d).Append(e); + + private static StringBuilder Append(this StringBuilder source, string a, string b, + string c, string d, string e, string f) + => source.Append(a).Append(b).Append(c).Append(d).Append(e).Append(f); + + private static StringBuilder Append(this StringBuilder source, string a, string b, + string c, string d, string e, string f, string g) + => source.Append(a).Append(b).Append(c).Append(d).Append(e).Append(f).Append(g); + + private static StringBuilder Append(this StringBuilder source, string a, string b, + string c, string d, string e, string f, string g, string h) + => source.Append(a).Append(b).Append(c).Append(d).Append(e).Append(f).Append(g).Append(h); + + private const string Marshaling = "global::Godot.NativeInterop.Marshaling"; + private const string VariantUtils = "global::Godot.NativeInterop.VariantUtils"; + + public static StringBuilder AppendVariantToManagedExpr(this StringBuilder source, + string inputExpr, ITypeSymbol typeSymbol, MarshalType marshalType) + { + return marshalType switch + { + MarshalType.Boolean => + source.Append(VariantUtils, ".ConvertToBool(", inputExpr, ")"), + MarshalType.Char => + source.Append("(char)", VariantUtils, ".ConvertToUInt16(", inputExpr, ")"), + MarshalType.SByte => + source.Append(VariantUtils, ".ConvertToInt8(", inputExpr, ")"), + MarshalType.Int16 => + source.Append(VariantUtils, ".ConvertToInt16(", inputExpr, ")"), + MarshalType.Int32 => + source.Append(VariantUtils, ".ConvertToInt32(", inputExpr, ")"), + MarshalType.Int64 => + source.Append(VariantUtils, ".ConvertToInt64(", inputExpr, ")"), + MarshalType.Byte => + source.Append(VariantUtils, ".ConvertToUInt8(", inputExpr, ")"), + MarshalType.UInt16 => + source.Append(VariantUtils, ".ConvertToUInt16(", inputExpr, ")"), + MarshalType.UInt32 => + source.Append(VariantUtils, ".ConvertToUInt32(", inputExpr, ")"), + MarshalType.UInt64 => + source.Append(VariantUtils, ".ConvertToUInt64(", inputExpr, ")"), + MarshalType.Single => + source.Append(VariantUtils, ".ConvertToFloat32(", inputExpr, ")"), + MarshalType.Double => + source.Append(VariantUtils, ".ConvertToFloat64(", inputExpr, ")"), + MarshalType.String => + source.Append(VariantUtils, ".ConvertToStringObject(", inputExpr, ")"), + MarshalType.Vector2 => + source.Append(VariantUtils, ".ConvertToVector2(", inputExpr, ")"), + MarshalType.Vector2i => + source.Append(VariantUtils, ".ConvertToVector2i(", inputExpr, ")"), + MarshalType.Rect2 => + source.Append(VariantUtils, ".ConvertToRect2(", inputExpr, ")"), + MarshalType.Rect2i => + source.Append(VariantUtils, ".ConvertToRect2i(", inputExpr, ")"), + MarshalType.Transform2D => + source.Append(VariantUtils, ".ConvertToTransform2D(", inputExpr, ")"), + MarshalType.Vector3 => + source.Append(VariantUtils, ".ConvertToVector3(", inputExpr, ")"), + MarshalType.Vector3i => + source.Append(VariantUtils, ".ConvertToVector3i(", inputExpr, ")"), + MarshalType.Basis => + source.Append(VariantUtils, ".ConvertToBasis(", inputExpr, ")"), + MarshalType.Quaternion => + source.Append(VariantUtils, ".ConvertToQuaternion(", inputExpr, ")"), + MarshalType.Transform3D => + source.Append(VariantUtils, ".ConvertToTransform3D(", inputExpr, ")"), + MarshalType.AABB => + source.Append(VariantUtils, ".ConvertToAABB(", inputExpr, ")"), + MarshalType.Color => + source.Append(VariantUtils, ".ConvertToColor(", inputExpr, ")"), + MarshalType.Plane => + source.Append(VariantUtils, ".ConvertToPlane(", inputExpr, ")"), + MarshalType.Callable => + source.Append(VariantUtils, ".ConvertToCallableManaged(", inputExpr, ")"), + MarshalType.SignalInfo => + source.Append(VariantUtils, ".ConvertToSignalInfo(", inputExpr, ")"), + MarshalType.Enum => + source.Append("(", typeSymbol.FullQualifiedName(), + ")", VariantUtils, ".ConvertToInt32(", inputExpr, ")"), + MarshalType.ByteArray => + source.Append(VariantUtils, ".ConvertAsPackedByteArrayToSystemArray(", inputExpr, ")"), + MarshalType.Int32Array => + source.Append(VariantUtils, ".ConvertAsPackedInt32ArrayToSystemArray(", inputExpr, ")"), + MarshalType.Int64Array => + source.Append(VariantUtils, ".ConvertAsPackedInt64ArrayToSystemArray(", inputExpr, ")"), + MarshalType.Float32Array => + source.Append(VariantUtils, ".ConvertAsPackedFloat32ArrayToSystemArray(", inputExpr, ")"), + MarshalType.Float64Array => + source.Append(VariantUtils, ".ConvertAsPackedFloat64ArrayToSystemArray(", inputExpr, ")"), + MarshalType.StringArray => + source.Append(VariantUtils, ".ConvertAsPackedStringArrayToSystemArray(", inputExpr, ")"), + MarshalType.Vector2Array => + source.Append(VariantUtils, ".ConvertAsPackedVector2ArrayToSystemArray(", inputExpr, ")"), + MarshalType.Vector3Array => + source.Append(VariantUtils, ".ConvertAsPackedVector3ArrayToSystemArray(", inputExpr, ")"), + MarshalType.ColorArray => + source.Append(VariantUtils, ".ConvertAsPackedColorArrayToSystemArray(", inputExpr, ")"), + MarshalType.GodotObjectOrDerivedArray => + source.Append(VariantUtils, ".ConvertToSystemArrayOfGodotObject<", + ((IArrayTypeSymbol)typeSymbol).ElementType.FullQualifiedName(), ">(", inputExpr, ")"), + MarshalType.SystemObjectArray => + source.Append(VariantUtils, ".ConvertToSystemArrayOfVariant(", inputExpr, ")"), + MarshalType.SystemArrayOfSupportedType => + source.Append(VariantUtils, ".ConvertToSystemArrayOfSupportedType<", + ((IArrayTypeSymbol)typeSymbol).ElementType.FullQualifiedName(), ">(", inputExpr, ")"), + MarshalType.GodotGenericDictionary => + source.Append(VariantUtils, ".ConvertToGenericDictionaryObject<", + ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedName(), ", ", + ((INamedTypeSymbol)typeSymbol).TypeArguments[1].FullQualifiedName(), ">(", inputExpr, ")"), + MarshalType.GodotGenericArray => + source.Append(VariantUtils, ".ConvertToGenericArrayObject<", + ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedName(), ">(", inputExpr, ")"), + MarshalType.SystemGenericDictionary => + source.Append(VariantUtils, ".ConvertToSystemGenericDictionary<", + ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedName(), ", ", + ((INamedTypeSymbol)typeSymbol).TypeArguments[1].FullQualifiedName(), ">(", inputExpr, ")"), + MarshalType.SystemGenericList => + source.Append(VariantUtils, ".ConvertToSystemGenericList<", + ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedName(), ">(", inputExpr, ")"), + MarshalType.GenericIDictionary => + source.Append(VariantUtils, ".ConvertToGenericDictionaryObject<", + ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedName(), ", ", + ((INamedTypeSymbol)typeSymbol).TypeArguments[1].FullQualifiedName(), ">(", inputExpr, ")"), + MarshalType.GenericICollection or MarshalType.GenericIEnumerable => + source.Append(VariantUtils, ".ConvertToGenericArrayObject<", + ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedName(), ">(", inputExpr, ")"), + MarshalType.SystemObject => + source.Append(Marshaling, ".ConvertVariantToManagedObject(", inputExpr, ")"), + MarshalType.GodotObjectOrDerived => + source.Append("(", typeSymbol.FullQualifiedName(), + ")", VariantUtils, ".ConvertToGodotObject(", inputExpr, ")"), + MarshalType.StringName => + source.Append(VariantUtils, ".ConvertToStringNameObject(", inputExpr, ")"), + MarshalType.NodePath => + source.Append(VariantUtils, ".ConvertToNodePathObject(", inputExpr, ")"), + MarshalType.RID => + source.Append(VariantUtils, ".ConvertToRID(", inputExpr, ")"), + MarshalType.GodotDictionary => + source.Append(VariantUtils, ".ConvertToDictionaryObject(", inputExpr, ")"), + MarshalType.GodotArray => + source.Append(VariantUtils, ".ConvertToArrayObject(", inputExpr, ")"), + MarshalType.IDictionary => + source.Append(VariantUtils, ".ConvertToDictionaryObject(", inputExpr, ")"), + MarshalType.ICollection or MarshalType.IEnumerable => + source.Append(VariantUtils, ".ConvertToArrayObject(", inputExpr, ")"), + _ => throw new ArgumentOutOfRangeException(nameof(marshalType), marshalType, + "Received unexpected marshal type") + }; + } + + public static StringBuilder AppendManagedToVariantExpr( + this StringBuilder source, string inputExpr, MarshalType marshalType) + { + return marshalType switch + { + MarshalType.Boolean => + source.Append(VariantUtils, ".CreateFromBool(", inputExpr, ")"), + MarshalType.Char => + source.Append(VariantUtils, ".CreateFromInt((ushort)", inputExpr, ")"), + MarshalType.SByte => + source.Append(VariantUtils, ".CreateFromInt(", inputExpr, ")"), + MarshalType.Int16 => + source.Append(VariantUtils, ".CreateFromInt(", inputExpr, ")"), + MarshalType.Int32 => + source.Append(VariantUtils, ".CreateFromInt(", inputExpr, ")"), + MarshalType.Int64 => + source.Append(VariantUtils, ".CreateFromInt(", inputExpr, ")"), + MarshalType.Byte => + source.Append(VariantUtils, ".CreateFromInt(", inputExpr, ")"), + MarshalType.UInt16 => + source.Append(VariantUtils, ".CreateFromInt(", inputExpr, ")"), + MarshalType.UInt32 => + source.Append(VariantUtils, ".CreateFromInt(", inputExpr, ")"), + MarshalType.UInt64 => + source.Append(VariantUtils, ".CreateFromInt(", inputExpr, ")"), + MarshalType.Single => + source.Append(VariantUtils, ".CreateFromFloat(", inputExpr, ")"), + MarshalType.Double => + source.Append(VariantUtils, ".CreateFromFloat(", inputExpr, ")"), + MarshalType.String => + source.Append(VariantUtils, ".CreateFromString(", inputExpr, ")"), + MarshalType.Vector2 => + source.Append(VariantUtils, ".CreateFromVector2(", inputExpr, ")"), + MarshalType.Vector2i => + source.Append(VariantUtils, ".CreateFromVector2i(", inputExpr, ")"), + MarshalType.Rect2 => + source.Append(VariantUtils, ".CreateFromRect2(", inputExpr, ")"), + MarshalType.Rect2i => + source.Append(VariantUtils, ".CreateFromRect2i(", inputExpr, ")"), + MarshalType.Transform2D => + source.Append(VariantUtils, ".CreateFromTransform2D(", inputExpr, ")"), + MarshalType.Vector3 => + source.Append(VariantUtils, ".CreateFromVector3(", inputExpr, ")"), + MarshalType.Vector3i => + source.Append(VariantUtils, ".CreateFromVector3i(", inputExpr, ")"), + MarshalType.Basis => + source.Append(VariantUtils, ".CreateFromBasis(", inputExpr, ")"), + MarshalType.Quaternion => + source.Append(VariantUtils, ".CreateFromQuaternion(", inputExpr, ")"), + MarshalType.Transform3D => + source.Append(VariantUtils, ".CreateFromTransform3D(", inputExpr, ")"), + MarshalType.AABB => + source.Append(VariantUtils, ".CreateFromAABB(", inputExpr, ")"), + MarshalType.Color => + source.Append(VariantUtils, ".CreateFromColor(", inputExpr, ")"), + MarshalType.Plane => + source.Append(VariantUtils, ".CreateFromPlane(", inputExpr, ")"), + MarshalType.Callable => + source.Append(VariantUtils, ".CreateFromCallable(", inputExpr, ")"), + MarshalType.SignalInfo => + source.Append(VariantUtils, ".CreateFromSignalInfo(", inputExpr, ")"), + MarshalType.Enum => + source.Append(VariantUtils, ".CreateFromInt((int)", inputExpr, ")"), + MarshalType.ByteArray => + source.Append(VariantUtils, ".CreateFromPackedByteArray(", inputExpr, ")"), + MarshalType.Int32Array => + source.Append(VariantUtils, ".CreateFromPackedInt32Array(", inputExpr, ")"), + MarshalType.Int64Array => + source.Append(VariantUtils, ".CreateFromPackedInt64Array(", inputExpr, ")"), + MarshalType.Float32Array => + source.Append(VariantUtils, ".CreateFromPackedFloat32Array(", inputExpr, ")"), + MarshalType.Float64Array => + source.Append(VariantUtils, ".CreateFromPackedFloat64Array(", inputExpr, ")"), + MarshalType.StringArray => + source.Append(VariantUtils, ".CreateFromPackedStringArray(", inputExpr, ")"), + MarshalType.Vector2Array => + source.Append(VariantUtils, ".CreateFromPackedVector2Array(", inputExpr, ")"), + MarshalType.Vector3Array => + source.Append(VariantUtils, ".CreateFromPackedVector3Array(", inputExpr, ")"), + MarshalType.ColorArray => + source.Append(VariantUtils, ".CreateFromPackedColorArray(", inputExpr, ")"), + MarshalType.GodotObjectOrDerivedArray => + source.Append(VariantUtils, ".CreateFromSystemArrayOfGodotObject(", inputExpr, ")"), + MarshalType.SystemObjectArray => + source.Append(VariantUtils, ".CreateFromSystemArrayOfVariant(", inputExpr, ")"), + MarshalType.SystemArrayOfSupportedType => + source.Append(VariantUtils, ".CreateFromSystemArrayOfSupportedType(", inputExpr, ")"), + MarshalType.GodotGenericDictionary => + source.Append(VariantUtils, ".CreateFromDictionary(", inputExpr, ")"), + MarshalType.GodotGenericArray => + source.Append(VariantUtils, ".CreateFromArray(", inputExpr, ")"), + MarshalType.SystemGenericDictionary => + source.Append(VariantUtils, ".CreateFromSystemDictionary(", inputExpr, ")"), + MarshalType.SystemGenericList => + source.Append(VariantUtils, ".CreateFromSystemICollection(", inputExpr, ")"), + MarshalType.GenericIDictionary => + source.Append(VariantUtils, ".CreateFromSystemGenericIDictionary(", inputExpr, ")"), + MarshalType.GenericICollection => + source.Append(VariantUtils, ".CreateFromSystemGenericICollection(", inputExpr, ")"), + MarshalType.GenericIEnumerable => + source.Append(VariantUtils, ".CreateFromSystemGenericIEnumerable(", inputExpr, ")"), + MarshalType.SystemObject => + source.Append(Marshaling, ".ConvertManagedObjectToVariant(", inputExpr, ")"), + MarshalType.GodotObjectOrDerived => + source.Append(VariantUtils, ".CreateFromGodotObject(", inputExpr, ")"), + MarshalType.StringName => + source.Append(VariantUtils, ".CreateFromStringName(", inputExpr, ")"), + MarshalType.NodePath => + source.Append(VariantUtils, ".CreateFromNodePath(", inputExpr, ")"), + MarshalType.RID => + source.Append(VariantUtils, ".CreateFromRID(", inputExpr, ")"), + MarshalType.GodotDictionary => + source.Append(VariantUtils, ".CreateFromDictionary(", inputExpr, ")"), + MarshalType.GodotArray => + source.Append(VariantUtils, ".CreateFromArray(", inputExpr, ")"), + MarshalType.IDictionary => + source.Append(VariantUtils, ".CreateFromSystemIDictionary(", inputExpr, ")"), + MarshalType.ICollection => + source.Append(VariantUtils, ".CreateFromSystemICollection(", inputExpr, ")"), + MarshalType.IEnumerable => + source.Append(VariantUtils, ".CreateFromSystemIEnumerable(", inputExpr, ")"), + _ => throw new ArgumentOutOfRangeException(nameof(marshalType), marshalType, + "Received unexpected marshal type") + }; + } } } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMemberInvokerGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMemberInvokerGenerator.cs index 6d3d03c495..303326e11a 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMemberInvokerGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMemberInvokerGenerator.cs @@ -105,8 +105,6 @@ namespace Godot.SourceGenerators var members = symbol.GetMembers(); - // TODO: Static static marshaling (no reflection, no runtime type checks) - var methodSymbols = members .Where(s => !s.IsStatic && s.Kind == SymbolKind.Method && !s.IsImplicitlyDeclared) .Cast<IMethodSymbol>() @@ -182,7 +180,7 @@ namespace Godot.SourceGenerators continue; GeneratePropertySetter(property.PropertySymbol.Name, - property.PropertySymbol.Type.FullQualifiedName(), source, isFirstEntry); + property.PropertySymbol.Type, property.Type, source, isFirstEntry); isFirstEntry = false; } @@ -192,7 +190,7 @@ namespace Godot.SourceGenerators continue; GeneratePropertySetter(field.FieldSymbol.Name, - field.FieldSymbol.Type.FullQualifiedName(), source, isFirstEntry); + field.FieldSymbol.Type, field.Type, source, isFirstEntry); isFirstEntry = false; } @@ -209,13 +207,15 @@ namespace Godot.SourceGenerators isFirstEntry = true; foreach (var property in godotClassProperties) { - GeneratePropertyGetter(property.PropertySymbol.Name, source, isFirstEntry); + GeneratePropertyGetter(property.PropertySymbol.Name, + property.Type, source, isFirstEntry); isFirstEntry = false; } foreach (var field in godotClassFields) { - GeneratePropertyGetter(field.FieldSymbol.Name, source, isFirstEntry); + GeneratePropertyGetter(field.FieldSymbol.Name, + field.Type, source, isFirstEntry); isFirstEntry = false; } @@ -278,7 +278,7 @@ namespace Godot.SourceGenerators source.Append(") {\n"); if (method.RetType != null) - source.Append(" object retBoxed = "); + source.Append(" var callRet = "); else source.Append(" "); @@ -290,25 +290,19 @@ namespace Godot.SourceGenerators if (i != 0) source.Append(", "); - // TODO: static marshaling (no reflection, no runtime type checks) - - string paramTypeQualifiedName = method.ParamTypeSymbols[i].FullQualifiedName(); - - source.Append("("); - source.Append(paramTypeQualifiedName); - source.Append(")Marshaling.ConvertVariantToManagedObjectOfType(args["); - source.Append(i); - source.Append("], typeof("); - source.Append(paramTypeQualifiedName); - source.Append("))"); + source.AppendVariantToManagedExpr(string.Concat("args[", i.ToString(), "]"), + method.ParamTypeSymbols[i], method.ParamTypes[i]); } source.Append(");\n"); if (method.RetType != null) { - // TODO: static marshaling (no reflection, no runtime type checks) - source.Append(" ret = Marshaling.ConvertManagedObjectToVariant(retBoxed);\n"); + source.Append(" ret = "); + + source.AppendManagedToVariantExpr("callRet", method.RetType.Value); + source.Append(";\n"); + source.Append(" return true;\n"); } else @@ -322,56 +316,49 @@ namespace Godot.SourceGenerators private static void GeneratePropertySetter( string propertyMemberName, - string propertyTypeQualifiedName, + ITypeSymbol propertyTypeSymbol, + MarshalType propertyMarshalType, StringBuilder source, bool isFirstEntry ) { source.Append(" "); + if (!isFirstEntry) source.Append("else "); - source.Append("if (name == GodotInternal.PropName_"); - source.Append(propertyMemberName); - source.Append(") {\n"); - - source.Append(" "); - source.Append(propertyMemberName); - source.Append(" = "); - // TODO: static marshaling (no reflection, no runtime type checks) - - source.Append("("); - source.Append(propertyTypeQualifiedName); - source.Append(")Marshaling.ConvertVariantToManagedObjectOfType(value, typeof("); - source.Append(propertyTypeQualifiedName); - source.Append("));\n"); - - source.Append(" return true;\n"); - - source.Append(" }\n"); + source.Append("if (name == GodotInternal.PropName_") + .Append(propertyMemberName) + .Append(") {\n") + .Append(" ") + .Append(propertyMemberName) + .Append(" = ") + .AppendVariantToManagedExpr("value", propertyTypeSymbol, propertyMarshalType) + .Append(";\n") + .Append(" return true;\n") + .Append(" }\n"); } private static void GeneratePropertyGetter( string propertyMemberName, + MarshalType propertyMarshalType, StringBuilder source, bool isFirstEntry ) { source.Append(" "); + if (!isFirstEntry) source.Append("else "); - source.Append("if (name == GodotInternal.PropName_"); - source.Append(propertyMemberName); - source.Append(") {\n"); - // TODO: static marshaling (no reflection, no runtime type checks) - - source.Append(" value = Marshaling.ConvertManagedObjectToVariant("); - source.Append(propertyMemberName); - source.Append(");\n"); - source.Append(" return true;\n"); - - source.Append(" }\n"); + source.Append("if (name == GodotInternal.PropName_") + .Append(propertyMemberName) + .Append(") {\n") + .Append(" value = ") + .AppendManagedToVariantExpr(propertyMemberName, propertyMarshalType) + .Append(";\n") + .Append(" return true;\n") + .Append(" }\n"); } private static void GenerateHasMethodEntry( diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs index 85fa65d1af..e10521b78e 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs @@ -152,7 +152,7 @@ namespace Godot.SourceGenerators { source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n"); - string dictionaryType = "System.Collections.Generic.List<Godot.Bridge.PropertyInfo>"; + string dictionaryType = "System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo>"; source.Append(" internal new static ") .Append(dictionaryType) @@ -214,7 +214,7 @@ namespace Godot.SourceGenerators private static void AppendPropertyInfo(StringBuilder source, PropertyInfo propertyInfo) { - source.Append(" properties.Add(new Godot.Bridge.PropertyInfo(type: (Godot.Variant.Type)") + source.Append(" properties.Add(new(type: (Godot.Variant.Type)") .Append((int)propertyInfo.Type) .Append(", name: GodotInternal.PropName_") .Append(propertyInfo.Name) diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj index 92a40b9b8b..eb54effc01 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj +++ b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj @@ -3,7 +3,7 @@ <ProjectGuid>{27B00618-A6F2-4828-B922-05CAEB08C286}</ProjectGuid> <TargetFramework>net5.0</TargetFramework> <EnableDynamicLoading>true</EnableDynamicLoading> - <LangVersion>8</LangVersion> + <LangVersion>9</LangVersion> <!-- The Godot editor uses the Debug Godot API assemblies --> <GodotApiConfiguration>Debug</GodotApiConfiguration> <GodotSourceRootPath>$(SolutionDir)/../../../../</GodotSourceRootPath> diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 6c805c605d..f416336d11 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -1653,7 +1653,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str << INDENT3 "{\n"; if (imethod.return_type.cname != name_cache.type_void) { - output << INDENT4 "object retBoxed = "; + output << INDENT4 "var callRet = "; } else { output << INDENT4; } @@ -1670,27 +1670,30 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str output << ", "; } - // TODO: static marshaling (no reflection, no runtime type checks) if (arg_type->cname == name_cache.type_Array_generic || arg_type->cname == name_cache.type_Dictionary_generic) { String arg_cs_type = arg_type->cs_type + _get_generic_type_parameters(*arg_type, iarg.type.generic_type_parameters); - output << "new " << arg_cs_type << "((" << arg_type->cs_type << ")Marshaling.ConvertVariantToManagedObjectOfType(args[" - << itos(i) << "], typeof(" << arg_type->cs_type << ")))"; + output << "new " << arg_cs_type << "(" << sformat(arg_type->cs_variant_to_managed, + "args[" + itos(i) + "]", arg_type->cs_type, arg_type->name) << ")"; } else { - output << "(" << arg_type->cs_type << ")Marshaling.ConvertVariantToManagedObjectOfType(args[" - << itos(i) << "], typeof(" << arg_type->cs_type << "))"; + output << sformat(arg_type->cs_variant_to_managed, + "args[" + itos(i) + "]", arg_type->cs_type, arg_type->name); } } output << ");\n"; if (imethod.return_type.cname != name_cache.type_void) { - // TODO: static marshaling (no reflection, no runtime type checks) - output << INDENT4 "ret = Marshaling.ConvertManagedObjectToVariant(retBoxed);\n"; - output << INDENT4 "return true;\n"; + const TypeInterface *return_type = _get_type_or_null(imethod.return_type); + ERR_FAIL_NULL_V(return_type, ERR_BUG); // Return type not found + + output << INDENT4 "ret = " + << sformat(return_type->cs_managed_to_variant, "callRet", return_type->cs_type, return_type->name) + << ";\n" + << INDENT4 "return true;\n"; } else { - output << INDENT4 "ret = default;\n"; - output << INDENT4 "return true;\n"; + output << INDENT4 "ret = default;\n" + << INDENT4 "return true;\n"; } output << INDENT3 "}\n"; @@ -2321,7 +2324,7 @@ Error BindingsGenerator::_generate_cs_native_calls(const InternalCall &p_icall, String c_in_vararg = arg_type->c_in_vararg; if (arg_type->is_object_type) { - c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromGodotObject(%1);\n"; + c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromGodotObjectPtr(%1);\n"; } ERR_FAIL_COND_V_MSG(c_in_vararg.is_empty(), ERR_BUG, @@ -2746,6 +2749,9 @@ bool BindingsGenerator::_populate_object_type_interfaces() { itype.is_ref_counted = ClassDB::is_parent_class(type_cname, name_cache.type_RefCounted); itype.memory_own = itype.is_ref_counted; + itype.cs_variant_to_managed = "(%1)VariantUtils.ConvertToGodotObject(%0)"; + itype.cs_managed_to_variant = "VariantUtils.CreateFromGodotObject(%0)"; + itype.c_out = "%5return "; itype.c_out += C_METHOD_UNMANAGED_GET_MANAGED; itype.c_out += itype.is_ref_counted ? "(%1.Reference);\n" : "(%1);\n"; @@ -3141,6 +3147,8 @@ bool BindingsGenerator::_populate_object_type_interfaces() { enum_itype.cname = StringName(enum_itype.name); enum_itype.proxy_name = itype.proxy_name + "." + enum_proxy_name; TypeInterface::postsetup_enum_type(enum_itype); + enum_itype.cs_variant_to_managed = "(%1)VariantUtils.ConvertToInt32(%0)"; + enum_itype.cs_managed_to_variant = "VariantUtils.CreateFromInt((int)%0)"; enum_types.insert(enum_itype.cname, enum_itype); } @@ -3361,14 +3369,16 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { TypeInterface itype; -#define INSERT_STRUCT_TYPE(m_type) \ - { \ - itype = TypeInterface::create_value_type(String(#m_type)); \ - itype.c_type_in = #m_type "*"; \ - itype.c_type_out = itype.cs_type; \ - itype.cs_in_expr = "&%0"; \ - itype.cs_in_expr_is_unsafe = true; \ - builtin_types.insert(itype.cname, itype); \ +#define INSERT_STRUCT_TYPE(m_type) \ + { \ + itype = TypeInterface::create_value_type(String(#m_type)); \ + itype.c_type_in = #m_type "*"; \ + itype.c_type_out = itype.cs_type; \ + itype.cs_in_expr = "&%0"; \ + itype.cs_in_expr_is_unsafe = true; \ + itype.cs_variant_to_managed = "VariantUtils.ConvertTo%2(%0)"; \ + itype.cs_managed_to_variant = "VariantUtils.CreateFrom%2(%0)"; \ + builtin_types.insert(itype.cname, itype); \ } INSERT_STRUCT_TYPE(Vector2) @@ -3399,13 +3409,15 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.c_type_out = itype.c_type; itype.c_arg_in = "&%s"; itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromBool(%1);\n"; + itype.cs_variant_to_managed = "VariantUtils.ConvertToBool(%0)"; + itype.cs_managed_to_variant = "VariantUtils.CreateFromBool(%0)"; builtin_types.insert(itype.cname, itype); // Integer types { // C interface for 'uint32_t' is the same as that of enums. Remember to apply // any of the changes done here to 'TypeInterface::postsetup_enum_type' as well. -#define INSERT_INT_TYPE(m_name) \ +#define INSERT_INT_TYPE(m_name, m_int_struct_name) \ { \ itype = TypeInterface::create_value_type(String(m_name)); \ if (itype.name != "long" && itype.name != "ulong") { \ @@ -3419,22 +3431,24 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.c_type_in = itype.name; \ itype.c_type_out = itype.name; \ itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromInt(%1);\n"; \ + itype.cs_variant_to_managed = "VariantUtils.ConvertTo" m_int_struct_name "(%0)"; \ + itype.cs_managed_to_variant = "VariantUtils.CreateFromInt(%0)"; \ builtin_types.insert(itype.cname, itype); \ } // The expected type for all integers in ptrcall is 'int64_t', so that's what we use for 'c_type' - INSERT_INT_TYPE("sbyte"); - INSERT_INT_TYPE("short"); - INSERT_INT_TYPE("int"); - INSERT_INT_TYPE("long"); - INSERT_INT_TYPE("byte"); - INSERT_INT_TYPE("ushort"); - INSERT_INT_TYPE("uint"); - INSERT_INT_TYPE("ulong"); - } + INSERT_INT_TYPE("sbyte", "Int8"); + INSERT_INT_TYPE("short", "Int16"); + INSERT_INT_TYPE("int", "Int32"); + INSERT_INT_TYPE("long", "Int64"); + INSERT_INT_TYPE("byte", "UInt8"); + INSERT_INT_TYPE("ushort", "UInt16"); + INSERT_INT_TYPE("uint", "UInt32"); + INSERT_INT_TYPE("ulong", "UInt64"); #undef INSERT_INT_TYPE + } // Floating point types { @@ -3454,6 +3468,8 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.c_type_in = itype.proxy_name; itype.c_type_out = itype.proxy_name; itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromFloat(%1);\n"; + itype.cs_variant_to_managed = "VariantUtils.ConvertToFloat32(%0)"; + itype.cs_managed_to_variant = "VariantUtils.CreateFromFloat(%0)"; builtin_types.insert(itype.cname, itype); // double @@ -3467,6 +3483,8 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.c_type_in = itype.proxy_name; itype.c_type_out = itype.proxy_name; itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromFloat(%1);\n"; + itype.cs_variant_to_managed = "VariantUtils.ConvertToFloat64(%0)"; + itype.cs_managed_to_variant = "VariantUtils.CreateFromFloat(%0)"; builtin_types.insert(itype.cname, itype); } @@ -3483,7 +3501,9 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.c_type_in = itype.cs_type; itype.c_type_out = itype.cs_type; itype.c_type_is_disposable_struct = true; - itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromStringTakingOwnershipOfDisposableValue(" C_METHOD_MONOSTR_TO_GODOT "(%1));\n"; + itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromString(%1);\n"; + itype.cs_variant_to_managed = "VariantUtils.ConvertToStringObject(%0)"; + itype.cs_managed_to_variant = "VariantUtils.CreateFromString(%0)"; builtin_types.insert(itype.cname, itype); // StringName @@ -3502,6 +3522,8 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromStringName(%1);\n"; itype.c_type_is_disposable_struct = false; // [c_out] takes ownership itype.c_ret_needs_default_initialization = true; + itype.cs_variant_to_managed = "VariantUtils.ConvertToStringNameObject(%0)"; + itype.cs_managed_to_variant = "VariantUtils.CreateFromStringName(%0)"; builtin_types.insert(itype.cname, itype); // NodePath @@ -3519,6 +3541,8 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.c_type_out = itype.cs_type; itype.c_type_is_disposable_struct = false; // [c_out] takes ownership itype.c_ret_needs_default_initialization = true; + itype.cs_variant_to_managed = "VariantUtils.ConvertToNodePathObject(%0)"; + itype.cs_managed_to_variant = "VariantUtils.CreateFromNodePath(%0)"; builtin_types.insert(itype.cname, itype); // RID @@ -3531,6 +3555,8 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.c_type = itype.cs_type; itype.c_type_in = itype.c_type; itype.c_type_out = itype.c_type; + itype.cs_variant_to_managed = "VariantUtils.ConvertToRID(%0)"; + itype.cs_managed_to_variant = "VariantUtils.CreateFromRID(%0)"; builtin_types.insert(itype.cname, itype); // Variant @@ -3546,18 +3572,22 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.c_type_in = itype.cs_type; itype.c_type_out = itype.cs_type; itype.c_type_is_disposable_struct = true; + itype.cs_variant_to_managed = C_METHOD_MANAGED_FROM_VARIANT "(%0)"; + itype.cs_managed_to_variant = C_METHOD_MANAGED_TO_VARIANT "(%0)"; builtin_types.insert(itype.cname, itype); // Callable itype = TypeInterface::create_value_type(String("Callable")); - itype.cs_in_expr = "ref %0"; - itype.c_in = "%5using %0 %1_in = " C_METHOD_MANAGED_TO_CALLABLE "(ref %1);\n"; + itype.cs_in_expr = "%0"; + itype.c_in = "%5using %0 %1_in = " C_METHOD_MANAGED_TO_CALLABLE "(in %1);\n"; itype.c_out = "%5return " C_METHOD_MANAGED_FROM_CALLABLE "(in %1);\n"; itype.c_arg_in = "&%s_in"; itype.c_type = "godot_callable"; - itype.c_type_in = "ref " + itype.cs_type; + itype.c_type_in = "in " + itype.cs_type; itype.c_type_out = itype.cs_type; itype.c_type_is_disposable_struct = true; + itype.cs_variant_to_managed = "VariantUtils.ConvertToCallableManaged(%0)"; + itype.cs_managed_to_variant = "VariantUtils.CreateFromCallable(%0)"; builtin_types.insert(itype.cname, itype); // Signal @@ -3566,14 +3596,16 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.cname = itype.name; itype.proxy_name = "SignalInfo"; itype.cs_type = itype.proxy_name; - itype.cs_in_expr = "ref %0"; - itype.c_in = "%5using %0 %1_in = " C_METHOD_MANAGED_TO_SIGNAL "(ref %1);\n"; + itype.cs_in_expr = "%0"; + itype.c_in = "%5using %0 %1_in = " C_METHOD_MANAGED_TO_SIGNAL "(in %1);\n"; itype.c_out = "%5return " C_METHOD_MANAGED_FROM_SIGNAL "(&%1);\n"; itype.c_arg_in = "&%s_in"; itype.c_type = "godot_signal"; - itype.c_type_in = "ref " + itype.cs_type; + itype.c_type_in = "in " + itype.cs_type; itype.c_type_out = itype.cs_type; itype.c_type_is_disposable_struct = true; + itype.cs_variant_to_managed = "VariantUtils.ConvertToSignalInfo(%0)"; + itype.cs_managed_to_variant = "VariantUtils.CreateFromSignalInfo(%0)"; builtin_types.insert(itype.cname, itype); // VarArg (fictitious type to represent variable arguments) @@ -3587,6 +3619,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { // c_out and c_type_out are not applicable to VarArg. itype.c_arg_in = "&%s_in"; itype.c_type_in = "object[]"; + itype.cs_variant_to_managed = "VariantUtils.ConvertToSystemArray(%0)"; builtin_types.insert(itype.cname, itype); #define INSERT_ARRAY_FULL(m_name, m_type, m_managed_type, m_proxy_t) \ @@ -3603,6 +3636,8 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.c_type_in = itype.proxy_name; \ itype.c_type_out = itype.proxy_name; \ itype.c_type_is_disposable_struct = true; \ + itype.cs_variant_to_managed = "VariantUtils.ConvertAs%2ToSystemArray(%0)"; \ + itype.cs_managed_to_variant = "VariantUtils.CreateFrom%2(%0)"; \ builtin_types.insert(itype.name, itype); \ } @@ -3638,6 +3673,8 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.c_type_out = itype.cs_type; itype.c_type_is_disposable_struct = false; // [c_out] takes ownership itype.c_ret_needs_default_initialization = true; + itype.cs_variant_to_managed = "VariantUtils.ConvertToArrayObject(%0)"; + itype.cs_managed_to_variant = "VariantUtils.CreateFromArray(%0)"; builtin_types.insert(itype.cname, itype); // Array_@generic @@ -3662,6 +3699,8 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.c_type_out = itype.cs_type; itype.c_type_is_disposable_struct = false; // [c_out] takes ownership itype.c_ret_needs_default_initialization = true; + itype.cs_variant_to_managed = "VariantUtils.ConvertToDictionaryObject(%0)"; + itype.cs_managed_to_variant = "VariantUtils.CreateFromDictionary(%0)"; builtin_types.insert(itype.cname, itype); // Dictionary_@generic @@ -3734,6 +3773,8 @@ void BindingsGenerator::_populate_global_constants() { enum_itype.cname = ienum.cname; enum_itype.proxy_name = enum_itype.name; TypeInterface::postsetup_enum_type(enum_itype); + enum_itype.cs_variant_to_managed = "(%1)VariantUtils.ConvertToInt32(%0)"; + enum_itype.cs_managed_to_variant = "VariantUtils.CreateFromInt((int)%0)"; enum_types.insert(enum_itype.cname, enum_itype); int prefix_length = _determine_enum_prefix(ienum); @@ -3766,6 +3807,8 @@ void BindingsGenerator::_populate_global_constants() { enum_itype.cname = enum_cname; enum_itype.proxy_name = enum_itype.name; TypeInterface::postsetup_enum_type(enum_itype); + enum_itype.cs_variant_to_managed = "(%1)VariantUtils.ConvertToInt32(%0)"; + enum_itype.cs_managed_to_variant = "VariantUtils.CreateFromInt((int)%0)"; enum_types.insert(enum_itype.cname, enum_itype); } } diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index d53e67896e..afdb898b88 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -385,6 +385,22 @@ class BindingsGenerator { */ String cs_type; + /** + * Formatting elements: + * %0: input expression of type `in godot_variant` + * %1: [cs_type] of this type + * %2: [name] of this type + */ + String cs_variant_to_managed; + + /** + * Formatting elements: + * %0: input expression + * %1: [cs_type] of this type + * %2: [name] of this type + */ + String cs_managed_to_variant; + const DocData::ClassDoc *class_doc = nullptr; List<ConstantInterface> constants; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs index cd6655b857..a09ba09e95 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs @@ -320,6 +320,37 @@ namespace Godot.Collections } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal object GetAtAsType(int index, Type type) + { + GetVariantBorrowElementAt(index, out godot_variant borrowElem); + return Marshaling.ConvertVariantToManagedObjectOfType(borrowElem, type); + } + + internal void CopyToGeneric<T>(T[] array, int arrayIndex, Type type = null) + { + if (array == null) + throw new ArgumentNullException(nameof(array), "Value cannot be null."); + + if (arrayIndex < 0) + throw new ArgumentOutOfRangeException(nameof(arrayIndex), + "Number was less than the array's lower bound in the first dimension."); + + var typeOfElements = type ?? typeof(T); + + int count = Count; + + if (array.Length < (arrayIndex + count)) + throw new ArgumentException( + "Destination array was not long enough. Check destIndex and length, and the array's lower bounds."); + + for (int i = 0; i < count; i++) + { + array[arrayIndex] = (T)GetAtAsType(i, typeOfElements); + arrayIndex++; + } + } + // IEnumerable /// <summary> @@ -517,11 +548,7 @@ namespace Godot.Collections /// <value>The value at the given <paramref name="index"/>.</value> public T this[int index] { - get - { - _underlyingArray.GetVariantBorrowElementAt(index, out godot_variant borrowElem); - return (T)Marshaling.ConvertVariantToManagedObjectOfType(borrowElem, TypeOfElements); - } + get => (T)_underlyingArray.GetAtAsType(index, TypeOfElements); set => _underlyingArray[index] = value; } @@ -604,27 +631,8 @@ namespace Godot.Collections /// </summary> /// <param name="array">The C# array to copy to.</param> /// <param name="arrayIndex">The index to start at.</param> - public void CopyTo(T[] array, int arrayIndex) - { - if (array == null) - throw new ArgumentNullException(nameof(array), "Value cannot be null."); - - if (arrayIndex < 0) - throw new ArgumentOutOfRangeException(nameof(arrayIndex), - "Number was less than the array's lower bound in the first dimension."); - - int count = _underlyingArray.Count; - - if (array.Length < (arrayIndex + count)) - throw new ArgumentException( - "Destination array was not long enough. Check destIndex and length, and the array's lower bounds."); - - for (int i = 0; i < count; i++) - { - array[arrayIndex] = this[i]; - arrayIndex++; - } - } + public void CopyTo(T[] array, int arrayIndex) => + _underlyingArray.CopyToGeneric<T>(array, arrayIndex, TypeOfElements); /// <summary> /// Removes the first occurrence of the specified value diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs index 4a99872e7b..2bea2f3b4f 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs @@ -373,7 +373,7 @@ namespace Godot.Collections /// </summary> /// <typeparam name="TKey">The type of the dictionary's keys.</typeparam> /// <typeparam name="TValue">The type of the dictionary's values.</typeparam> - public sealed class Dictionary<TKey, TValue> : + public class Dictionary<TKey, TValue> : IDictionary<TKey, TValue>, IGenericGodotDictionary { private readonly Dictionary _underlyingDict; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs index d1a1450f04..fc11f56680 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs @@ -11,6 +11,8 @@ using System.Runtime.InteropServices; #nullable enable +// TODO: Consider removing support for IEnumerable + namespace Godot.NativeInterop { public static class Marshaling @@ -280,121 +282,74 @@ namespace Godot.NativeInterop case Plane @plane: return VariantUtils.CreateFromPlane(@plane); case Callable @callable: - return VariantUtils.CreateFromCallableTakingOwnershipOfDisposableValue( - ConvertCallableToNative(ref @callable)); + return VariantUtils.CreateFromCallable(@callable); case SignalInfo @signalInfo: - return VariantUtils.CreateFromSignalTakingOwnershipOfDisposableValue( - ConvertSignalToNative(ref @signalInfo)); + return VariantUtils.CreateFromSignalInfo(@signalInfo); case Enum @enum: return VariantUtils.CreateFromInt(Convert.ToInt64(@enum)); case string @string: - { - return VariantUtils.CreateFromStringTakingOwnershipOfDisposableValue( - ConvertStringToNative(@string)); - } + return VariantUtils.CreateFromString(@string); case byte[] byteArray: - { - using godot_packed_byte_array array = ConvertSystemArrayToNativePackedByteArray(byteArray); - return VariantUtils.CreateFromPackedByteArray(array); - } + return VariantUtils.CreateFromPackedByteArray(byteArray); case Int32[] int32Array: - { - using godot_packed_int32_array array = ConvertSystemArrayToNativePackedInt32Array(int32Array); - return VariantUtils.CreateFromPackedInt32Array(array); - } + return VariantUtils.CreateFromPackedInt32Array(int32Array); case Int64[] int64Array: - { - using godot_packed_int64_array array = ConvertSystemArrayToNativePackedInt64Array(int64Array); - return VariantUtils.CreateFromPackedInt64Array(array); - } + return VariantUtils.CreateFromPackedInt64Array(int64Array); case float[] floatArray: - { - using godot_packed_float32_array array = ConvertSystemArrayToNativePackedFloat32Array(floatArray); - return VariantUtils.CreateFromPackedFloat32Array(array); - } + return VariantUtils.CreateFromPackedFloat32Array(floatArray); case double[] doubleArray: - { - using godot_packed_float64_array array = ConvertSystemArrayToNativePackedFloat64Array(doubleArray); - return VariantUtils.CreateFromPackedFloat64Array(array); - } + return VariantUtils.CreateFromPackedFloat64Array(doubleArray); case string[] stringArray: - { - using godot_packed_string_array array = ConvertSystemArrayToNativePackedStringArray(stringArray); - return VariantUtils.CreateFromPackedStringArray(array); - } + return VariantUtils.CreateFromPackedStringArray(stringArray); case Vector2[] vector2Array: - { - using godot_packed_vector2_array array = ConvertSystemArrayToNativePackedVector2Array(vector2Array); - return VariantUtils.CreateFromPackedVector2Array(array); - } + return VariantUtils.CreateFromPackedVector2Array(vector2Array); case Vector3[] vector3Array: - { - using godot_packed_vector3_array array = ConvertSystemArrayToNativePackedVector3Array(vector3Array); - return VariantUtils.CreateFromPackedVector3Array(array); - } + return VariantUtils.CreateFromPackedVector3Array(vector3Array); case Color[] colorArray: - { - using godot_packed_color_array array = ConvertSystemArrayToNativePackedColorArray(colorArray); - return VariantUtils.CreateFromPackedColorArray(array); - } + return VariantUtils.CreateFromPackedColorArray(colorArray); case StringName[] stringNameArray: - { - using godot_array array = ConvertSystemArrayToNativeGodotArray(stringNameArray); - return VariantUtils.CreateFromArray(array); - } + return VariantUtils.CreateFromSystemArrayOfSupportedType(stringNameArray); case NodePath[] nodePathArray: - { - using godot_array array = ConvertSystemArrayToNativeGodotArray(nodePathArray); - return VariantUtils.CreateFromArray(array); - } + return VariantUtils.CreateFromSystemArrayOfSupportedType(nodePathArray); case RID[] ridArray: - { - using godot_array array = ConvertSystemArrayToNativeGodotArray(ridArray); - return VariantUtils.CreateFromArray(array); - } + return VariantUtils.CreateFromSystemArrayOfSupportedType(ridArray); case Godot.Object[] godotObjectArray: - { - using godot_array array = ConvertSystemArrayToNativeGodotArray(godotObjectArray); - return VariantUtils.CreateFromArray(array); - } + return VariantUtils.CreateFromSystemArrayOfGodotObject(godotObjectArray); case object[] objectArray: // Last one to avoid catching others like string[] and Godot.Object[] { // The pattern match for `object[]` catches arrays on any reference type, // so we need to check the actual type to make sure it's truly `object[]`. if (objectArray.GetType() == typeof(object[])) - { - using godot_array array = ConvertSystemArrayToNativeGodotArray(objectArray); - return VariantUtils.CreateFromArray(array); - } + return VariantUtils.CreateFromSystemArrayOfVariant(objectArray); GD.PushError("Attempted to convert a managed array of unmarshallable element type to Variant."); return new godot_variant(); } case Godot.Object godotObject: - return VariantUtils.CreateFromGodotObject(godotObject.NativeInstance); + return VariantUtils.CreateFromGodotObject(godotObject); case StringName stringName: - return VariantUtils.CreateFromStringName(stringName.NativeValue.DangerousSelfRef); + return VariantUtils.CreateFromStringName(stringName); case NodePath nodePath: - return VariantUtils.CreateFromNodePath((godot_node_path)nodePath.NativeValue); + return VariantUtils.CreateFromNodePath(nodePath); case RID rid: return VariantUtils.CreateFromRID(rid); case Collections.Dictionary godotDictionary: - return VariantUtils.CreateFromDictionary((godot_dictionary)godotDictionary.NativeValue); + return VariantUtils.CreateFromDictionary(godotDictionary); case Collections.Array godotArray: - return VariantUtils.CreateFromArray((godot_array)godotArray.NativeValue); + return VariantUtils.CreateFromArray(godotArray); case Collections.IGenericGodotDictionary genericGodotDictionary: { var godotDict = genericGodotDictionary.UnderlyingDictionary; if (godotDict == null) return new godot_variant(); - return VariantUtils.CreateFromDictionary((godot_dictionary)godotDict.NativeValue); + return VariantUtils.CreateFromDictionary(godotDict); } case Collections.IGenericGodotArray genericGodotArray: { var godotArray = genericGodotArray.UnderlyingArray; if (godotArray == null) return new godot_variant(); - return VariantUtils.CreateFromArray((godot_array)godotArray.NativeValue); + return VariantUtils.CreateFromArray(godotArray); } default: { @@ -412,13 +367,13 @@ namespace Godot.NativeInterop foreach (KeyValuePair<object, object> entry in (IDictionary)p_obj) godotDict.Add(entry.Key, entry.Value); - return VariantUtils.CreateFromDictionary((godot_dictionary)godotDict.NativeValue); + return VariantUtils.CreateFromDictionary(godotDict); } if (genericTypeDefinition == typeof(System.Collections.Generic.List<>)) { // TODO: Validate element type is compatible with Variant - using var nativeGodotArray = ConvertIListToNativeGodotArray((IList)p_obj); + using var nativeGodotArray = ConvertICollectionToNativeGodotArray((ICollection)p_obj); return VariantUtils.CreateFromArray(nativeGodotArray); } } @@ -432,25 +387,6 @@ namespace Godot.NativeInterop return new godot_variant(); } - private static string? ConvertVariantToManagedString(in godot_variant p_var) - { - switch (p_var.Type) - { - case Variant.Type.Nil: - return null; // Otherwise, Variant -> String would return the string "Null" - case Variant.Type.String: - { - // We avoid the internal call if the stored type is the same we want. - return ConvertStringToManaged(p_var.String); - } - default: - { - using godot_string godotString = NativeFuncs.godotsharp_variant_as_string(p_var); - return ConvertStringToManaged(godotString); - } - } - } - public static object? ConvertVariantToManagedObjectOfType(in godot_variant p_var, Type type) { // This function is only needed to set the value of properties. Fields have their own implementation, set_value_from_variant. @@ -481,7 +417,7 @@ namespace Godot.NativeInterop case TypeCode.Double: return VariantUtils.ConvertToFloat64(p_var); case TypeCode.String: - return ConvertVariantToManagedString(p_var); + return VariantUtils.ConvertToStringObject(p_var); default: { if (type == typeof(Vector2)) @@ -533,16 +469,10 @@ namespace Godot.NativeInterop return VariantUtils.ConvertToPlane(p_var); if (type == typeof(Callable)) - { - using godot_callable callable = NativeFuncs.godotsharp_variant_as_callable(p_var); - return ConvertCallableToManaged(in callable); - } + return VariantUtils.ConvertToCallableManaged(p_var); if (type == typeof(SignalInfo)) - { - using godot_signal signal = NativeFuncs.godotsharp_variant_as_signal(p_var); - return ConvertSignalToManaged(in signal); - } + return VariantUtils.ConvertToSignalInfo(p_var); if (type.IsEnum) { @@ -596,88 +526,46 @@ namespace Godot.NativeInterop private static object? ConvertVariantToSystemArrayOfType(in godot_variant p_var, Type type) { if (type == typeof(byte[])) - { - using var packedArray = NativeFuncs.godotsharp_variant_as_packed_byte_array(p_var); - return ConvertNativePackedByteArrayToSystemArray(packedArray); - } + return VariantUtils.ConvertAsPackedByteArrayToSystemArray(p_var); if (type == typeof(Int32[])) - { - using var packedArray = NativeFuncs.godotsharp_variant_as_packed_int32_array(p_var); - return ConvertNativePackedInt32ArrayToSystemArray(packedArray); - } + return VariantUtils.ConvertAsPackedInt32ArrayToSystemArray(p_var); if (type == typeof(Int64[])) - { - using var packedArray = NativeFuncs.godotsharp_variant_as_packed_int64_array(p_var); - return ConvertNativePackedInt64ArrayToSystemArray(packedArray); - } + return VariantUtils.ConvertAsPackedInt64ArrayToSystemArray(p_var); if (type == typeof(float[])) - { - using var packedArray = NativeFuncs.godotsharp_variant_as_packed_float32_array(p_var); - return ConvertNativePackedFloat32ArrayToSystemArray(packedArray); - } + return VariantUtils.ConvertAsPackedFloat32ArrayToSystemArray(p_var); if (type == typeof(double[])) - { - using var packedArray = NativeFuncs.godotsharp_variant_as_packed_float64_array(p_var); - return ConvertNativePackedFloat64ArrayToSystemArray(packedArray); - } + return VariantUtils.ConvertAsPackedFloat64ArrayToSystemArray(p_var); if (type == typeof(string[])) - { - using var packedArray = NativeFuncs.godotsharp_variant_as_packed_string_array(p_var); - return ConvertNativePackedStringArrayToSystemArray(packedArray); - } + return VariantUtils.ConvertAsPackedStringArrayToSystemArray(p_var); if (type == typeof(Vector2[])) - { - using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector2_array(p_var); - return ConvertNativePackedVector2ArrayToSystemArray(packedArray); - } + return VariantUtils.ConvertAsPackedVector2ArrayToSystemArray(p_var); if (type == typeof(Vector3[])) - { - using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector3_array(p_var); - return ConvertNativePackedVector3ArrayToSystemArray(packedArray); - } + return VariantUtils.ConvertAsPackedVector3ArrayToSystemArray(p_var); if (type == typeof(Color[])) - { - using var packedArray = NativeFuncs.godotsharp_variant_as_packed_color_array(p_var); - return ConvertNativePackedColorArrayToSystemArray(packedArray); - } + return VariantUtils.ConvertAsPackedColorArrayToSystemArray(p_var); if (type == typeof(StringName[])) - { - using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); - return ConvertNativeGodotArrayToSystemArrayOfType(godotArray, type); - } + return VariantUtils.ConvertToSystemArrayOfSupportedType<StringName>(p_var); if (type == typeof(NodePath[])) - { - using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); - return ConvertNativeGodotArrayToSystemArrayOfType(godotArray, type); - } + return VariantUtils.ConvertToSystemArrayOfSupportedType<NodePath>(p_var); if (type == typeof(RID[])) - { - using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); - return ConvertNativeGodotArrayToSystemArrayOfType(godotArray, type); - } + return VariantUtils.ConvertToSystemArrayOfSupportedType<RID>(p_var); if (typeof(Godot.Object[]).IsAssignableFrom(type)) - { - using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); - return ConvertNativeGodotArrayToSystemArrayOfType(godotArray, type); - } + return VariantUtils.ConvertToSystemArrayOfGodotObject(p_var, type); if (type == typeof(object[])) - { - using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); - return ConvertNativeGodotArrayToSystemArray(godotArray); - } + return VariantUtils.ConvertToSystemArrayOfVariant(p_var); GD.PushError("Attempted to convert Variant to array of unsupported element type. Name: " + type.GetElementType()!.FullName + "."); @@ -689,21 +577,29 @@ namespace Godot.NativeInterop { if (typeof(Godot.Object).IsAssignableFrom(type)) { - res = InteropUtils.UnmanagedGetManaged(VariantUtils.ConvertToGodotObject(p_var)); + var godotObject = VariantUtils.ConvertToGodotObject(p_var); + + if (!type.IsInstanceOfType(godotObject)) + { + GD.PushError("Invalid cast when marshaling Godot.Object type." + + $" `{godotObject.GetType()}` is not assignable to `{type.FullName}`."); + res = null; + return false; + } + + res = godotObject; return true; } if (typeof(StringName) == type) { - res = StringName.CreateTakingOwnershipOfDisposableValue( - VariantUtils.ConvertToStringName(p_var)); + res = VariantUtils.ConvertToStringNameObject(p_var); return true; } if (typeof(NodePath) == type) { - res = NodePath.CreateTakingOwnershipOfDisposableValue( - VariantUtils.ConvertToNodePath(p_var)); + res = VariantUtils.ConvertToNodePathObject(p_var); return true; } @@ -715,8 +611,7 @@ namespace Godot.NativeInterop if (typeof(Collections.Dictionary) == type || typeof(System.Collections.IDictionary) == type) { - res = Collections.Dictionary.CreateTakingOwnershipOfDisposableValue( - VariantUtils.ConvertToDictionary(p_var)); + res = VariantUtils.ConvertToDictionaryObject(p_var); return true; } @@ -724,8 +619,7 @@ namespace Godot.NativeInterop typeof(System.Collections.ICollection) == type || typeof(System.Collections.IEnumerable) == type) { - res = Collections.Array.CreateTakingOwnershipOfDisposableValue( - VariantUtils.ConvertToArray(p_var)); + res = VariantUtils.ConvertToArrayObject(p_var); return true; } @@ -737,8 +631,7 @@ namespace Godot.NativeInterop { static object ConvertVariantToGenericGodotCollectionsDictionary(in godot_variant p_var, Type fullType) { - var underlyingDict = Collections.Dictionary.CreateTakingOwnershipOfDisposableValue( - VariantUtils.ConvertToDictionary(p_var)); + var underlyingDict = VariantUtils.ConvertToDictionaryObject(p_var); return Activator.CreateInstance(fullType, BindingFlags.Public | BindingFlags.Instance, null, args: new object[] { underlyingDict }, null)!; @@ -746,8 +639,7 @@ namespace Godot.NativeInterop static object ConvertVariantToGenericGodotCollectionsArray(in godot_variant p_var, Type fullType) { - var underlyingArray = Collections.Array.CreateTakingOwnershipOfDisposableValue( - VariantUtils.ConvertToArray(p_var)); + var underlyingArray = VariantUtils.ConvertToArrayObject(p_var); return Activator.CreateInstance(fullType, BindingFlags.Public | BindingFlags.Instance, null, args: new object[] { underlyingArray }, null)!; @@ -763,8 +655,7 @@ namespace Godot.NativeInterop if (genericTypeDefinition == typeof(System.Collections.Generic.Dictionary<,>)) { - using var godotDictionary = Collections.Dictionary.CreateTakingOwnershipOfDisposableValue( - VariantUtils.ConvertToDictionary(p_var)); + using var godotDictionary = VariantUtils.ConvertToDictionaryObject(p_var); var dictionary = (System.Collections.IDictionary)Activator.CreateInstance(type, BindingFlags.Public | BindingFlags.Instance, null, @@ -781,8 +672,7 @@ namespace Godot.NativeInterop if (genericTypeDefinition == typeof(System.Collections.Generic.List<>)) { - using var godotArray = Collections.Array.CreateTakingOwnershipOfDisposableValue( - VariantUtils.ConvertToArray(p_var)); + using var godotArray = VariantUtils.ConvertToArrayObject(p_var); var list = (System.Collections.IList)Activator.CreateInstance(type, BindingFlags.Public | BindingFlags.Instance, null, @@ -818,7 +708,18 @@ namespace Godot.NativeInterop } if (typeof(Godot.Object).IsAssignableFrom(type)) - return InteropUtils.UnmanagedGetManaged(VariantUtils.ConvertToGodotObject(p_var)); + { + var godotObject = VariantUtils.ConvertToGodotObject(p_var); + + if (!type.IsInstanceOfType(godotObject)) + { + GD.PushError("Invalid cast when marshaling Godot.Object type." + + $" `{godotObject.GetType()}` is not assignable to `{type.FullName}`."); + return null; + } + + return godotObject; + } return null; } @@ -906,50 +807,23 @@ namespace Godot.NativeInterop NativeFuncs.godotsharp_array_new_copy(p_var.Array)); } case Variant.Type.PackedByteArray: - { - using var packedArray = NativeFuncs.godotsharp_variant_as_packed_byte_array(p_var); - return ConvertNativePackedByteArrayToSystemArray(packedArray); - } + return VariantUtils.ConvertAsPackedByteArrayToSystemArray(p_var); case Variant.Type.PackedInt32Array: - { - using var packedArray = NativeFuncs.godotsharp_variant_as_packed_int32_array(p_var); - return ConvertNativePackedInt32ArrayToSystemArray(packedArray); - } + return VariantUtils.ConvertAsPackedInt32ArrayToSystemArray(p_var); case Variant.Type.PackedInt64Array: - { - using var packedArray = NativeFuncs.godotsharp_variant_as_packed_int64_array(p_var); - return ConvertNativePackedInt64ArrayToSystemArray(packedArray); - } + return VariantUtils.ConvertAsPackedInt64ArrayToSystemArray(p_var); case Variant.Type.PackedFloat32Array: - { - using var packedArray = NativeFuncs.godotsharp_variant_as_packed_float32_array(p_var); - return ConvertNativePackedFloat32ArrayToSystemArray(packedArray); - } + return VariantUtils.ConvertAsPackedFloat32ArrayToSystemArray(p_var); case Variant.Type.PackedFloat64Array: - { - using var packedArray = NativeFuncs.godotsharp_variant_as_packed_float64_array(p_var); - return ConvertNativePackedFloat64ArrayToSystemArray(packedArray); - } + return VariantUtils.ConvertAsPackedFloat64ArrayToSystemArray(p_var); case Variant.Type.PackedStringArray: - { - using var packedArray = NativeFuncs.godotsharp_variant_as_packed_string_array(p_var); - return ConvertNativePackedStringArrayToSystemArray(packedArray); - } + return VariantUtils.ConvertAsPackedStringArrayToSystemArray(p_var); case Variant.Type.PackedVector2Array: - { - using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector2_array(p_var); - return ConvertNativePackedVector2ArrayToSystemArray(packedArray); - } + return VariantUtils.ConvertAsPackedVector2ArrayToSystemArray(p_var); case Variant.Type.PackedVector3Array: - { - using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector3_array(p_var); - return ConvertNativePackedVector3ArrayToSystemArray(packedArray); - } + return VariantUtils.ConvertAsPackedVector3ArrayToSystemArray(p_var); case Variant.Type.PackedColorArray: - { - using var packedArray = NativeFuncs.godotsharp_variant_as_packed_color_array(p_var); - return ConvertNativePackedColorArrayToSystemArray(packedArray); - } + return VariantUtils.ConvertAsPackedColorArrayToSystemArray(p_var); default: return null; } @@ -986,10 +860,7 @@ namespace Godot.NativeInterop // Callable - public static godot_callable ConvertCallableToNative(ref Callable p_managed_callable) - => ConvertCallableToNative(p_managed_callable); - - public static godot_callable ConvertCallableToNative(Callable p_managed_callable) + public static godot_callable ConvertCallableToNative(in Callable p_managed_callable) { if (p_managed_callable.Delegate != null) { @@ -1041,7 +912,7 @@ namespace Godot.NativeInterop // SignalInfo - public static godot_signal ConvertSignalToNative(ref SignalInfo p_managed_signal) + public static godot_signal ConvertSignalToNative(in SignalInfo p_managed_signal) { ulong ownerId = p_managed_signal.Owner.GetInstanceId(); godot_string_name name; @@ -1082,17 +953,46 @@ namespace Godot.NativeInterop return ret; } - private static object ConvertNativeGodotArrayToSystemArrayOfType(in godot_array p_array, Type type) + internal static T[] ConvertNativeGodotArrayToSystemArrayOfType<T>(in godot_array p_array) + { + var array = Collections.Array.CreateTakingOwnershipOfDisposableValue( + NativeFuncs.godotsharp_array_new_copy(p_array)); + + int length = array.Count; + var ret = new T[length]; + + // ConvertVariantToManagedObjectOfType handled by Collections.Array.CopyToGeneric<T> + array.CopyToGeneric(ret, 0); + + return ret; + } + + internal static T[] ConvertNativeGodotArrayToSystemArrayOfGodotObjectType<T>(in godot_array p_array) + where T : Godot.Object { var array = Collections.Array.CreateTakingOwnershipOfDisposableValue( NativeFuncs.godotsharp_array_new_copy(p_array)); int length = array.Count; - object ret = Activator.CreateInstance(type, length)!; + var ret = new T[length]; - // ConvertVariantToManagedObject handled by Collections.Array - // ConvertVariantToManagedObjectOfType is not needed because target element types are Godot.Object (or derived) - array.CopyTo((object[])ret, 0); + // ConvertVariantToManagedObjectOfType handled by Collections.Array.CopyToGeneric<T> + array.CopyToGeneric(ret, 0); + + return ret; + } + + internal static Godot.Object[] ConvertNativeGodotArrayToSystemArrayOfGodotObjectType(in godot_array p_array, + Type type) + { + var array = Collections.Array.CreateTakingOwnershipOfDisposableValue( + NativeFuncs.godotsharp_array_new_copy(p_array)); + + int length = array.Count; + var ret = (Godot.Object[])Activator.CreateInstance(type, length)!; + + // ConvertVariantToManagedObjectOfType handled by Collections.Array.CopyToGeneric<T> + array.CopyToGeneric(ret, 0, type.GetElementType()); return ret; } @@ -1131,7 +1031,7 @@ namespace Godot.NativeInterop return NativeFuncs.godotsharp_array_new_copy(src); } - public static godot_array ConvertIListToNativeGodotArray(IList p_array) + public static godot_array ConvertICollectionToNativeGodotArray(ICollection p_array) { int length = p_array.Count; @@ -1141,13 +1041,62 @@ namespace Godot.NativeInterop using var array = new Collections.Array(); array.Resize(length); - for (int i = 0; i < length; i++) - array[i] = p_array[i]; + int i = 0; + foreach (var elem in p_array) + { + array[i] = elem; + i++; + } var src = (godot_array)array.NativeValue; return NativeFuncs.godotsharp_array_new_copy(src); } + public static godot_array ConvertGenericICollectionToNativeGodotArray<T>(ICollection<T> p_array) + { + int length = p_array.Count; + + if (length == 0) + return NativeFuncs.godotsharp_array_new(); + + var array = new Collections.Array<T>(); + using var underlyingArray = (Collections.Array)array; + array.Resize(length); + + int i = 0; + foreach (var elem in p_array) + { + array[i] = elem; + i++; + } + + var src = (godot_array)underlyingArray.NativeValue; + return NativeFuncs.godotsharp_array_new_copy(src); + } + + public static godot_array ConvertIEnumerableToNativeGodotArray(IEnumerable p_array) + { + using var array = new Collections.Array(); + + foreach (var elem in p_array) + array.Add(elem); + + var src = (godot_array)array.NativeValue; + return NativeFuncs.godotsharp_array_new_copy(src); + } + + public static godot_array ConvertGenericIEnumerableToNativeGodotArray<T>(IEnumerable<T> p_array) + { + var array = new Collections.Array<T>(); + using var underlyingArray = (Collections.Array)array; + + foreach (var elem in p_array) + array.Add(elem); + + var src = (godot_array)underlyingArray.NativeValue; + return NativeFuncs.godotsharp_array_new_copy(src); + } + // PackedByteArray public static unsafe byte[] ConvertNativePackedByteArrayToSystemArray(in godot_packed_byte_array p_array) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs index f69cc40314..72be871f16 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs @@ -1,7 +1,11 @@ using System; +using System.Runtime.CompilerServices; +using Godot.Collections; // ReSharper disable InconsistentNaming +#nullable enable + namespace Godot.NativeInterop { public static class VariantUtils @@ -94,14 +98,28 @@ namespace Godot.NativeInterop public static godot_variant CreateFromCallableTakingOwnershipOfDisposableValue(godot_callable from) => new() { Type = Variant.Type.Callable, Callable = from }; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static godot_variant CreateFromCallable(Callable from) + => CreateFromCallableTakingOwnershipOfDisposableValue( + Marshaling.ConvertCallableToNative(from)); + // Explicit name to make it very clear public static godot_variant CreateFromSignalTakingOwnershipOfDisposableValue(godot_signal from) => new() { Type = Variant.Type.Signal, Signal = from }; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static godot_variant CreateFromSignalInfo(SignalInfo from) + => CreateFromSignalTakingOwnershipOfDisposableValue( + Marshaling.ConvertSignalToNative(from)); + // Explicit name to make it very clear public static godot_variant CreateFromStringTakingOwnershipOfDisposableValue(godot_string from) => new() { Type = Variant.Type.String, String = from }; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static godot_variant CreateFromString(string? from) + => CreateFromStringTakingOwnershipOfDisposableValue(Marshaling.ConvertStringToNative(from)); + public static godot_variant CreateFromPackedByteArray(in godot_packed_byte_array from) { NativeFuncs.godotsharp_variant_new_packed_byte_array(out godot_variant ret, from); @@ -156,31 +174,192 @@ namespace Godot.NativeInterop return ret; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static godot_variant CreateFromPackedByteArray(Span<byte> from) + => CreateFromPackedByteArray(Marshaling.ConvertSystemArrayToNativePackedByteArray(from)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static godot_variant CreateFromPackedInt32Array(Span<int> from) + => CreateFromPackedInt32Array(Marshaling.ConvertSystemArrayToNativePackedInt32Array(from)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static godot_variant CreateFromPackedInt64Array(Span<long> from) + => CreateFromPackedInt64Array(Marshaling.ConvertSystemArrayToNativePackedInt64Array(from)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static godot_variant CreateFromPackedFloat32Array(Span<float> from) + => CreateFromPackedFloat32Array(Marshaling.ConvertSystemArrayToNativePackedFloat32Array(from)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static godot_variant CreateFromPackedFloat64Array(Span<double> from) + => CreateFromPackedFloat64Array(Marshaling.ConvertSystemArrayToNativePackedFloat64Array(from)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static godot_variant CreateFromPackedStringArray(Span<string> from) + => CreateFromPackedStringArray(Marshaling.ConvertSystemArrayToNativePackedStringArray(from)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static godot_variant CreateFromPackedVector2Array(Span<Vector2> from) + => CreateFromPackedVector2Array(Marshaling.ConvertSystemArrayToNativePackedVector2Array(from)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static godot_variant CreateFromPackedVector3Array(Span<Vector3> from) + => CreateFromPackedVector3Array(Marshaling.ConvertSystemArrayToNativePackedVector3Array(from)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static godot_variant CreateFromPackedColorArray(Span<Color> from) + => CreateFromPackedColorArray(Marshaling.ConvertSystemArrayToNativePackedColorArray(from)); + + public static godot_variant CreateFromSystemArrayOfSupportedType<T>(T[]? from) + { + if (from == null) + return default; // Nil + using godot_array array = Marshaling.ConvertSystemArrayToNativeGodotArray(from); + return CreateFromArray(array); + } + + // ReSharper disable once RedundantNameQualifier + public static godot_variant CreateFromSystemArrayOfGodotObject(Godot.Object[]? from) + { + if (from == null) + return default; // Nil + using godot_array array = Marshaling.ConvertSystemArrayToNativeGodotArray(from); + return CreateFromArray(array); + } + + public static godot_variant CreateFromSystemArrayOfVariant(object[]? from) + { + if (from == null) + return default; // Nil + using godot_array array = Marshaling.ConvertSystemArrayToNativeGodotArray(from); + return CreateFromArray(array); + } + public static godot_variant CreateFromArray(godot_array from) { NativeFuncs.godotsharp_variant_new_array(out godot_variant ret, from); return ret; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static godot_variant CreateFromArray(Collections.Array? from) + => from != null ? CreateFromArray((godot_array)from.NativeValue) : default; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + // ReSharper disable once RedundantNameQualifier + public static godot_variant CreateFromArray<T>(Collections.Array<T>? from) + => from != null ? CreateFromArray((godot_array)((Collections.Array)from).NativeValue) : default; + + public static godot_variant CreateFromSystemICollection(System.Collections.ICollection? from) + { + if (from == null) + return default; // Nil + using var nativeGodotArray = Marshaling.ConvertICollectionToNativeGodotArray(from); + return CreateFromArray(nativeGodotArray); + } + + public static godot_variant CreateFromSystemGenericICollection<T>( + System.Collections.Generic.ICollection<T>? from) + { + if (from == null) + return default; // Nil + using var nativeGodotArray = Marshaling.ConvertGenericICollectionToNativeGodotArray(from); + return CreateFromArray(nativeGodotArray); + } + + public static godot_variant CreateFromSystemIEnumerable(System.Collections.IEnumerable? from) + { + if (from == null) + return default; // Nil + using var nativeGodotArray = Marshaling.ConvertIEnumerableToNativeGodotArray(from); + return CreateFromArray(nativeGodotArray); + } + + public static godot_variant CreateFromSystemGenericIEnumerable<T>( + System.Collections.Generic.IEnumerable<T>? from) + { + if (from == null) + return default; // Nil + using var nativeGodotArray = Marshaling.ConvertGenericIEnumerableToNativeGodotArray(from); + return CreateFromArray(nativeGodotArray); + } + public static godot_variant CreateFromDictionary(godot_dictionary from) { NativeFuncs.godotsharp_variant_new_dictionary(out godot_variant ret, from); return ret; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static godot_variant CreateFromDictionary(Dictionary? from) + => from != null ? CreateFromDictionary((godot_dictionary)from.NativeValue) : default; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static godot_variant CreateFromDictionary<TKey, TValue>(Dictionary<TKey, TValue>? from) + => from != null ? CreateFromDictionary((godot_dictionary)((Dictionary)from).NativeValue) : default; + + public static godot_variant CreateFromSystemDictionary<TKey, TValue>( + System.Collections.Generic.Dictionary<TKey, TValue>? from) where TKey : notnull + { + if (from == null) + return default; // Nil + + var godotDict = new Dictionary(); + + foreach (var entry in from) + godotDict.Add(entry.Key, entry.Value); + + return CreateFromDictionary(godotDict); + } + + public static godot_variant CreateFromSystemIDictionary(System.Collections.IDictionary? from) + { + if (from == null) + return default; // Nil + + var godotDict = new Dictionary(); + + foreach (var entry in from) + godotDict.Add(entry, entry); + + return CreateFromDictionary(godotDict); + } + + public static godot_variant CreateFromSystemGenericIDictionary<TKey, TValue>( + System.Collections.Generic.IDictionary<TKey, TValue>? from) + { + if (from == null) + return default; // Nil + + var godotDict = new Dictionary<TKey, TValue>(); + + foreach (var entry in from) + godotDict.Add(entry.Key, entry.Value); + + return CreateFromDictionary(godotDict); + } + public static godot_variant CreateFromStringName(godot_string_name from) { NativeFuncs.godotsharp_variant_new_string_name(out godot_variant ret, from); return ret; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static godot_variant CreateFromStringName(StringName? from) + => from != null ? CreateFromStringName((godot_string_name)from.NativeValue) : default; + public static godot_variant CreateFromNodePath(godot_node_path from) { NativeFuncs.godotsharp_variant_new_node_path(out godot_variant ret, from); return ret; } - public static godot_variant CreateFromGodotObject(IntPtr from) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static godot_variant CreateFromNodePath(NodePath? from) + => from != null ? CreateFromNodePath((godot_node_path)from.NativeValue) : default; + + public static godot_variant CreateFromGodotObjectPtr(IntPtr from) { if (from == IntPtr.Zero) return new godot_variant(); @@ -188,6 +367,11 @@ namespace Godot.NativeInterop return ret; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + // ReSharper disable once RedundantNameQualifier + public static godot_variant CreateFromGodotObject(Godot.Object? from) + => from != null ? CreateFromGodotObjectPtr(Object.GetPtr(from)) : default; + // We avoid the internal call if the stored type is the same we want. public static bool ConvertToBool(in godot_variant p_var) @@ -328,32 +512,201 @@ namespace Godot.NativeInterop p_var.Plane : NativeFuncs.godotsharp_variant_as_plane(p_var); - public static IntPtr ConvertToGodotObject(in godot_variant p_var) - => p_var.Type == Variant.Type.Object ? p_var.Object : IntPtr.Zero; - public static RID ConvertToRID(in godot_variant p_var) => p_var.Type == Variant.Type.Rid ? p_var.RID : NativeFuncs.godotsharp_variant_as_rid(p_var); + public static IntPtr ConvertToGodotObjectPtr(in godot_variant p_var) + => p_var.Type == Variant.Type.Object ? p_var.Object : IntPtr.Zero; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + // ReSharper disable once RedundantNameQualifier + public static Godot.Object ConvertToGodotObject(in godot_variant p_var) + => InteropUtils.UnmanagedGetManaged(ConvertToGodotObjectPtr(p_var)); + + public static string ConvertToStringObject(in godot_variant p_var) + { + switch (p_var.Type) + { + case Variant.Type.Nil: + return ""; // Otherwise, Variant -> String would return the string "Null" + case Variant.Type.String: + { + // We avoid the internal call if the stored type is the same we want. + return Marshaling.ConvertStringToManaged(p_var.String); + } + default: + { + using godot_string godotString = NativeFuncs.godotsharp_variant_as_string(p_var); + return Marshaling.ConvertStringToManaged(godotString); + } + } + } + public static godot_string_name ConvertToStringName(in godot_variant p_var) => p_var.Type == Variant.Type.StringName ? NativeFuncs.godotsharp_string_name_new_copy(p_var.StringName) : NativeFuncs.godotsharp_variant_as_string_name(p_var); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static StringName ConvertToStringNameObject(in godot_variant p_var) + => StringName.CreateTakingOwnershipOfDisposableValue(ConvertToStringName(p_var)); + public static godot_node_path ConvertToNodePath(in godot_variant p_var) => p_var.Type == Variant.Type.NodePath ? NativeFuncs.godotsharp_node_path_new_copy(p_var.NodePath) : NativeFuncs.godotsharp_variant_as_node_path(p_var); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NodePath ConvertToNodePathObject(in godot_variant p_var) + => NodePath.CreateTakingOwnershipOfDisposableValue(ConvertToNodePath(p_var)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static godot_callable ConvertToCallable(in godot_variant p_var) + => NativeFuncs.godotsharp_variant_as_callable(p_var); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Callable ConvertToCallableManaged(in godot_variant p_var) + => Marshaling.ConvertCallableToManaged(ConvertToCallable(p_var)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static godot_signal ConvertToSignal(in godot_variant p_var) + => NativeFuncs.godotsharp_variant_as_signal(p_var); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static SignalInfo ConvertToSignalInfo(in godot_variant p_var) + => Marshaling.ConvertSignalToManaged(ConvertToSignal(p_var)); + public static godot_array ConvertToArray(in godot_variant p_var) => p_var.Type == Variant.Type.Array ? NativeFuncs.godotsharp_array_new_copy(p_var.Array) : NativeFuncs.godotsharp_variant_as_array(p_var); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Collections.Array ConvertToArrayObject(in godot_variant p_var) + => Collections.Array.CreateTakingOwnershipOfDisposableValue(ConvertToArray(p_var)); + public static godot_dictionary ConvertToDictionary(in godot_variant p_var) => p_var.Type == Variant.Type.Dictionary ? NativeFuncs.godotsharp_dictionary_new_copy(p_var.Dictionary) : NativeFuncs.godotsharp_variant_as_dictionary(p_var); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Dictionary ConvertToDictionaryObject(in godot_variant p_var) + => Dictionary.CreateTakingOwnershipOfDisposableValue(ConvertToDictionary(p_var)); + + public static byte[] ConvertAsPackedByteArrayToSystemArray(in godot_variant p_var) + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_byte_array(p_var); + return Marshaling.ConvertNativePackedByteArrayToSystemArray(packedArray); + } + + public static int[] ConvertAsPackedInt32ArrayToSystemArray(in godot_variant p_var) + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_int32_array(p_var); + return Marshaling.ConvertNativePackedInt32ArrayToSystemArray(packedArray); + } + + public static long[] ConvertAsPackedInt64ArrayToSystemArray(in godot_variant p_var) + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_int64_array(p_var); + return Marshaling.ConvertNativePackedInt64ArrayToSystemArray(packedArray); + } + + public static float[] ConvertAsPackedFloat32ArrayToSystemArray(in godot_variant p_var) + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_float32_array(p_var); + return Marshaling.ConvertNativePackedFloat32ArrayToSystemArray(packedArray); + } + + public static double[] ConvertAsPackedFloat64ArrayToSystemArray(in godot_variant p_var) + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_float64_array(p_var); + return Marshaling.ConvertNativePackedFloat64ArrayToSystemArray(packedArray); + } + + public static string[] ConvertAsPackedStringArrayToSystemArray(in godot_variant p_var) + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_string_array(p_var); + return Marshaling.ConvertNativePackedStringArrayToSystemArray(packedArray); + } + + public static Vector2[] ConvertAsPackedVector2ArrayToSystemArray(in godot_variant p_var) + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector2_array(p_var); + return Marshaling.ConvertNativePackedVector2ArrayToSystemArray(packedArray); + } + + public static Vector3[] ConvertAsPackedVector3ArrayToSystemArray(in godot_variant p_var) + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector3_array(p_var); + return Marshaling.ConvertNativePackedVector3ArrayToSystemArray(packedArray); + } + + public static Color[] ConvertAsPackedColorArrayToSystemArray(in godot_variant p_var) + { + using var packedArray = NativeFuncs.godotsharp_variant_as_packed_color_array(p_var); + return Marshaling.ConvertNativePackedColorArrayToSystemArray(packedArray); + } + + public static T[] ConvertToSystemArrayOfSupportedType<T>(in godot_variant p_var) + { + using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); + return Marshaling.ConvertNativeGodotArrayToSystemArrayOfType<T>(godotArray); + } + + public static T[] ConvertToSystemArrayOfGodotObject<T>(in godot_variant p_var) + // ReSharper disable once RedundantNameQualifier + where T : Godot.Object + { + using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); + return Marshaling.ConvertNativeGodotArrayToSystemArrayOfGodotObjectType<T>(godotArray); + } + + // ReSharper disable once RedundantNameQualifier + public static Godot.Object[] ConvertToSystemArrayOfGodotObject(in godot_variant p_var, Type type) + { + using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); + return Marshaling.ConvertNativeGodotArrayToSystemArrayOfGodotObjectType(godotArray, type); + } + + public static object[] ConvertToSystemArrayOfVariant(in godot_variant p_var) + { + using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); + return Marshaling.ConvertNativeGodotArrayToSystemArray(godotArray); + } + + public static Array<T> ConvertToGenericArrayObject<T>(in godot_variant p_var) => + new(ConvertToArrayObject(p_var)); + + public static Dictionary<TKey, TValue> ConvertToGenericDictionaryObject<TKey, TValue>(in godot_variant p_var) => + new(ConvertToDictionaryObject(p_var)); + + public static System.Collections.Generic.List<T> ConvertToSystemGenericList<T>(in godot_variant p_var) + { + var godotArray = ConvertToArrayObject(p_var); + + var res = new System.Collections.Generic.List<T>(godotArray.Count); + + foreach (object elem in godotArray) + res.Add((T)elem); + + return res; + } + + public static System.Collections.Generic.Dictionary<TKey, TValue> + ConvertToSystemGenericDictionary<TKey, TValue>(in godot_variant p_var) + where TKey : notnull + { + var godotDictionary = ConvertToDictionaryObject(p_var); + + var res = new System.Collections.Generic.Dictionary<TKey, TValue>(godotDictionary.Count); + + foreach (System.Collections.Generic.KeyValuePair<TKey, TValue> pair in godotDictionary) + res.Add(pair.Key, pair.Value); + + return res; + } } } |