diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs index 86c639f7b6c..a5b4cb81f60 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs @@ -80,28 +80,9 @@ namespace Godot.SourceGenerators.Sample [Export] private Vector3[] field_Vector3Array = { Vector3.Up, Vector3.Down, Vector3.Left, Vector3.Right }; [Export] private Color[] field_ColorArray = { Colors.Aqua, Colors.Aquamarine, Colors.Azure, Colors.Beige }; [Export] private Godot.Object[] field_GodotObjectOrDerivedArray = { null }; - - // Generics - [Export] private Godot.Collections.Dictionary field_GodotGenericDictionary = - new Godot.Collections.Dictionary { { "key1", "value1" }, { "key2", "value2" } }; - - [Export] private Godot.Collections.Array field_GodotGenericArray = - new Godot.Collections.Array { "elem1", "elem2", "elem3" }; - - [Export] private System.Collections.Generic.Dictionary field_SystemGenericDictionary = - new System.Collections.Generic.Dictionary { { "key1", "value1" }, { "key2", "value2" } }; - - [Export] private System.Collections.Generic.List field_SystemGenericList = - new System.Collections.Generic.List { "elem1", "elem2", "elem3" }; - - [Export] private System.Collections.Generic.IDictionary field_GenericIDictionary = - new System.Collections.Generic.Dictionary { { "key1", "value1" }, { "key2", "value2" } }; - - [Export] private System.Collections.Generic.ICollection field_GenericICollection = - new System.Collections.Generic.List { "elem1", "elem2", "elem3" }; - - [Export] private System.Collections.Generic.IEnumerable field_GenericIEnumerable = - new System.Collections.Generic.List { "elem1", "elem2", "elem3" }; + [Export] private StringName[] field_StringNameArray = { "foo", "bar" }; + [Export] private NodePath[] field_NodePathArray = { "foo", "bar" }; + [Export] private RID[] field_RIDArray = { default, default, default }; // Variant [Export] private Variant field_Variant = "foo"; @@ -118,15 +99,5 @@ namespace Godot.SourceGenerators.Sample [Export] private Godot.Collections.Array field_GodotArray = new() { "foo", 10, Vector2.Up, Colors.Chocolate }; - - [Export] private System.Collections.IDictionary field_IDictionary = - new System.Collections.Generic.Dictionary - { { "foo", 10 }, { Vector2.Up, Colors.Chocolate } }; - - [Export] private System.Collections.ICollection field_ICollection = - new System.Collections.Generic.List { "foo", 10, Vector2.Up, Colors.Chocolate }; - - [Export] private System.Collections.IEnumerable field_IEnumerable = - new System.Collections.Generic.List { "foo", 10, Vector2.Up, Colors.Chocolate }; } } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs index 665eb7f2a88..eb35c88260b 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs @@ -80,28 +80,9 @@ namespace Godot.SourceGenerators.Sample [Export] private Vector3[] property_Vector3Array { get; set; } = { Vector3.Up, Vector3.Down, Vector3.Left, Vector3.Right }; [Export] private Color[] property_ColorArray { get; set; } = { Colors.Aqua, Colors.Aquamarine, Colors.Azure, Colors.Beige }; [Export] private Godot.Object[] property_GodotObjectOrDerivedArray { get; set; } = { null }; - - // Generics - [Export] private Godot.Collections.Dictionary property_GodotGenericDictionary { get; set; } = - new Godot.Collections.Dictionary { { "key1", "value1" }, { "key2", "value2" } }; - - [Export] private Godot.Collections.Array property_GodotGenericArray { get; set; } = - new Godot.Collections.Array { "elem1", "elem2", "elem3" }; - - [Export] private System.Collections.Generic.Dictionary property_SystemGenericDictionary { get; set; } = - new System.Collections.Generic.Dictionary { { "key1", "value1" }, { "key2", "value2" } }; - - [Export] private System.Collections.Generic.List property_SystemGenericList { get; set; } = - new System.Collections.Generic.List { "elem1", "elem2", "elem3" }; - - [Export] private System.Collections.Generic.IDictionary property_GenericIDictionary { get; set; } = - new System.Collections.Generic.Dictionary { { "key1", "value1" }, { "key2", "value2" } }; - - [Export] private System.Collections.Generic.ICollection property_GenericICollection { get; set; } = - new System.Collections.Generic.List { "elem1", "elem2", "elem3" }; - - [Export] private System.Collections.Generic.IEnumerable property_GenericIEnumerable { get; set; } = - new System.Collections.Generic.List { "elem1", "elem2", "elem3" }; + [Export] private StringName[] field_StringNameArray { get; set; } = { "foo", "bar" }; + [Export] private NodePath[] field_NodePathArray { get; set; } = { "foo", "bar" }; + [Export] private RID[] field_RIDArray { get; set; } = { default, default, default }; // Variant [Export] private Variant property_Variant { get; set; } = "foo"; @@ -118,15 +99,5 @@ namespace Godot.SourceGenerators.Sample [Export] private Godot.Collections.Array property_GodotArray { get; set; } = new() { "foo", 10, Vector2.Up, Colors.Chocolate }; - - [Export] private System.Collections.IDictionary property_IDictionary { get; set; } = - new System.Collections.Generic.Dictionary - { { "foo", 10 }, { Vector2.Up, Colors.Chocolate } }; - - [Export] private System.Collections.ICollection property_ICollection { get; set; } = - new System.Collections.Generic.List { "foo", 10, Vector2.Up, Colors.Chocolate }; - - [Export] private System.Collections.IEnumerable property_IEnumerable { get; set; } = - new System.Collections.Generic.List { "foo", 10, Vector2.Up, Colors.Chocolate }; } } 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 e967cbe6629..3f767c8a5f7 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalType.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalType.cs @@ -53,16 +53,9 @@ namespace Godot.SourceGenerators Vector3Array, ColorArray, GodotObjectOrDerivedArray, - SystemArrayOfSupportedType, - - // Generics - GodotGenericDictionary, - GodotGenericArray, - SystemGenericDictionary, - SystemGenericList, - GenericIDictionary, - GenericICollection, - GenericIEnumerable, + SystemArrayOfStringName, + SystemArrayOfNodePath, + SystemArrayOfRID, // Variant Variant, @@ -74,8 +67,5 @@ namespace Godot.SourceGenerators RID, GodotDictionary, GodotArray, - IDictionary, - ICollection, - IEnumerable, } } 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 d132b6304fe..43000377968 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs @@ -10,17 +10,6 @@ namespace Godot.SourceGenerators public class TypeCache { 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; } - public INamedTypeSymbol SystemGenericList { get; } public TypeCache(GeneratorExecutionContext context) { @@ -31,13 +20,6 @@ namespace Godot.SourceGenerators } GodotObjectType = GetTypeByMetadataNameOrThrow("Godot.Object"); - GodotGenericDictionary = GetTypeByMetadataNameOrThrow("Godot.Collections.Dictionary`2"); - GodotGenericArray = GetTypeByMetadataNameOrThrow("Godot.Collections.Array`1"); - IDictionary = GetTypeByMetadataNameOrThrow("System.Collections.IDictionary"); - ICollection = GetTypeByMetadataNameOrThrow("System.Collections.ICollection"); - GenericIDictionary = GetTypeByMetadataNameOrThrow("System.Collections.Generic.IDictionary`2"); - SystemGenericDictionary = GetTypeByMetadataNameOrThrow("System.Collections.Generic.Dictionary`2"); - SystemGenericList = GetTypeByMetadataNameOrThrow("System.Collections.Generic.List`1"); } } @@ -86,14 +68,9 @@ namespace Godot.SourceGenerators MarshalType.Vector3Array => VariantType.PackedVector3Array, MarshalType.ColorArray => VariantType.PackedColorArray, MarshalType.GodotObjectOrDerivedArray => VariantType.Array, - MarshalType.SystemArrayOfSupportedType => VariantType.Array, - MarshalType.GodotGenericDictionary => VariantType.Dictionary, - MarshalType.GodotGenericArray => VariantType.Array, - MarshalType.SystemGenericDictionary => VariantType.Dictionary, - MarshalType.SystemGenericList => VariantType.Array, - MarshalType.GenericIDictionary => VariantType.Dictionary, - MarshalType.GenericICollection => VariantType.Array, - MarshalType.GenericIEnumerable => VariantType.Array, + MarshalType.SystemArrayOfStringName => VariantType.Array, + MarshalType.SystemArrayOfNodePath => VariantType.Array, + MarshalType.SystemArrayOfRID => VariantType.Array, MarshalType.Variant => VariantType.Nil, MarshalType.GodotObjectOrDerived => VariantType.Object, MarshalType.StringName => VariantType.StringName, @@ -101,9 +78,6 @@ namespace Godot.SourceGenerators MarshalType.RID => VariantType.Rid, MarshalType.GodotDictionary => VariantType.Dictionary, MarshalType.GodotArray => VariantType.Array, - MarshalType.IDictionary => VariantType.Dictionary, - MarshalType.ICollection => VariantType.Array, - MarshalType.IEnumerable => VariantType.Array, _ => null }; @@ -212,54 +186,22 @@ namespace Godot.SourceGenerators return MarshalType.Vector3Array; case { Name: "Color" }: return MarshalType.ColorArray; + case { Name: "StringName" }: + return MarshalType.SystemArrayOfStringName; + case { Name: "NodePath" }: + return MarshalType.SystemArrayOfNodePath; + case { Name: "RID" }: + return MarshalType.SystemArrayOfRID; } } - if (ConvertManagedTypeToMarshalType(elementType, typeCache) != null) - return MarshalType.SystemArrayOfSupportedType; - return null; } - else if (type is INamedTypeSymbol { IsGenericType: true } genericType) - { - var genericTypeDef = genericType.ConstructedFrom; - - if (SymbolEqualityComparer.Default.Equals(genericTypeDef, typeCache.GodotGenericDictionary)) - return MarshalType.GodotGenericDictionary; - - if (SymbolEqualityComparer.Default.Equals(genericTypeDef, typeCache.GodotGenericArray)) - return MarshalType.GodotGenericArray; - - if (SymbolEqualityComparer.Default.Equals(genericTypeDef, typeCache.SystemGenericDictionary)) - return MarshalType.SystemGenericDictionary; - - if (SymbolEqualityComparer.Default.Equals(genericTypeDef, typeCache.SystemGenericList)) - return MarshalType.SystemGenericList; - - if (SymbolEqualityComparer.Default.Equals(genericTypeDef, typeCache.GenericIDictionary)) - return MarshalType.GenericIDictionary; - - return genericTypeDef.SpecialType switch - { - SpecialType.System_Collections_Generic_ICollection_T => MarshalType.GenericICollection, - SpecialType.System_Collections_Generic_IEnumerable_T => MarshalType.GenericIEnumerable, - _ => null - }; - } else { if (type.SimpleDerivesFrom(typeCache.GodotObjectType)) return MarshalType.GodotObjectOrDerived; - if (SymbolEqualityComparer.Default.Equals(type, typeCache.IDictionary)) - return MarshalType.IDictionary; - - if (SymbolEqualityComparer.Default.Equals(type, typeCache.ICollection)) - return MarshalType.ICollection; - - if (specialType == SpecialType.System_Collections_IEnumerable) - return MarshalType.IEnumerable; - if (type.ContainingAssembly.Name == "GodotSharp") { switch (type.ContainingNamespace.Name) @@ -341,13 +283,9 @@ namespace Godot.SourceGenerators 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 VariantUtils = "global::Godot.NativeInterop.VariantUtils"; - public static StringBuilder AppendVariantToManagedExpr(this StringBuilder source, + public static StringBuilder AppendNativeVariantToManagedExpr(this StringBuilder source, string inputExpr, ITypeSymbol typeSymbol, MarshalType marshalType) { return marshalType switch @@ -438,30 +376,12 @@ namespace Godot.SourceGenerators MarshalType.GodotObjectOrDerivedArray => source.Append(VariantUtils, ".ConvertToSystemArrayOfGodotObject<", ((IArrayTypeSymbol)typeSymbol).ElementType.FullQualifiedName(), ">(", 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.SystemArrayOfStringName => + source.Append(VariantUtils, ".ConvertToSystemArrayOfStringName(", inputExpr, ")"), + MarshalType.SystemArrayOfNodePath => + source.Append(VariantUtils, ".ConvertToSystemArrayOfNodePath(", inputExpr, ")"), + MarshalType.SystemArrayOfRID => + source.Append(VariantUtils, ".ConvertToSystemArrayOfRID(", inputExpr, ")"), MarshalType.Variant => source.Append("global::Godot.Variant.CreateCopyingBorrowed(", inputExpr, ")"), MarshalType.GodotObjectOrDerived => @@ -477,16 +397,12 @@ namespace Godot.SourceGenerators 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( + public static StringBuilder AppendManagedToNativeVariantExpr( this StringBuilder source, string inputExpr, MarshalType marshalType) { return marshalType switch @@ -575,22 +491,12 @@ namespace Godot.SourceGenerators source.Append(VariantUtils, ".CreateFromPackedColorArray(", inputExpr, ")"), MarshalType.GodotObjectOrDerivedArray => source.Append(VariantUtils, ".CreateFromSystemArrayOfGodotObject(", 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.SystemArrayOfStringName => + source.Append(VariantUtils, ".CreateFromSystemArrayOfStringName(", inputExpr, ")"), + MarshalType.SystemArrayOfNodePath => + source.Append(VariantUtils, ".CreateFromSystemArrayOfNodePath(", inputExpr, ")"), + MarshalType.SystemArrayOfRID => + source.Append(VariantUtils, ".CreateFromSystemArrayOfRID(", inputExpr, ")"), MarshalType.Variant => source.Append(inputExpr, ".CopyNativeVariant()"), MarshalType.GodotObjectOrDerived => @@ -605,15 +511,140 @@ namespace Godot.SourceGenerators 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") }; } + + public static StringBuilder AppendVariantToManagedExpr(this StringBuilder source, + string inputExpr, ITypeSymbol typeSymbol, MarshalType marshalType) + { + return marshalType switch + { + MarshalType.Boolean => source.Append(inputExpr, ".AsBool()"), + MarshalType.Char => source.Append(inputExpr, ".AsChar()"), + MarshalType.SByte => source.Append(inputExpr, ".AsSByte()"), + MarshalType.Int16 => source.Append(inputExpr, ".AsInt16()"), + MarshalType.Int32 => source.Append(inputExpr, ".AsInt32()"), + MarshalType.Int64 => source.Append(inputExpr, ".AsInt64()"), + MarshalType.Byte => source.Append(inputExpr, ".AsByte()"), + MarshalType.UInt16 => source.Append(inputExpr, ".AsUInt16()"), + MarshalType.UInt32 => source.Append(inputExpr, ".AsUInt32()"), + MarshalType.UInt64 => source.Append(inputExpr, ".AsUInt64()"), + MarshalType.Single => source.Append(inputExpr, ".AsSingle()"), + MarshalType.Double => source.Append(inputExpr, ".AsDouble()"), + MarshalType.String => source.Append(inputExpr, ".AsString()"), + MarshalType.Vector2 => source.Append(inputExpr, ".AsVector2()"), + MarshalType.Vector2i => source.Append(inputExpr, ".AsVector2i()"), + MarshalType.Rect2 => source.Append(inputExpr, ".AsRect2()"), + MarshalType.Rect2i => source.Append(inputExpr, ".AsRect2i()"), + MarshalType.Transform2D => source.Append(inputExpr, ".AsTransform2D()"), + MarshalType.Vector3 => source.Append(inputExpr, ".AsVector3()"), + MarshalType.Vector3i => source.Append(inputExpr, ".AsVector3i()"), + MarshalType.Basis => source.Append(inputExpr, ".AsBasis()"), + MarshalType.Quaternion => source.Append(inputExpr, ".AsQuaternion()"), + MarshalType.Transform3D => source.Append(inputExpr, ".AsTransform3D()"), + MarshalType.Vector4 => source.Append(inputExpr, ".AsVector4()"), + MarshalType.Vector4i => source.Append(inputExpr, ".AsVector4i()"), + MarshalType.Projection => source.Append(inputExpr, ".AsProjection()"), + MarshalType.AABB => source.Append(inputExpr, ".AsAABB()"), + MarshalType.Color => source.Append(inputExpr, ".AsColor()"), + MarshalType.Plane => source.Append(inputExpr, ".AsPlane()"), + MarshalType.Callable => source.Append(inputExpr, ".AsCallable()"), + MarshalType.SignalInfo => source.Append(inputExpr, ".AsSignalInfo()"), + MarshalType.Enum => + source.Append("(", typeSymbol.FullQualifiedName(), ")", inputExpr, ".AsInt64()"), + MarshalType.ByteArray => source.Append(inputExpr, ".AsByteArray()"), + MarshalType.Int32Array => source.Append(inputExpr, ".AsInt32Array()"), + MarshalType.Int64Array => source.Append(inputExpr, ".AsInt64Array()"), + MarshalType.Float32Array => source.Append(inputExpr, ".AsFloat32Array()"), + MarshalType.Float64Array => source.Append(inputExpr, ".AsFloat64Array()"), + MarshalType.StringArray => source.Append(inputExpr, ".AsStringArray()"), + MarshalType.Vector2Array => source.Append(inputExpr, ".AsVector2Array()"), + MarshalType.Vector3Array => source.Append(inputExpr, ".AsVector3Array()"), + MarshalType.ColorArray => source.Append(inputExpr, ".AsColorArray()"), + MarshalType.GodotObjectOrDerivedArray => source.Append(inputExpr, ".AsGodotObjectArray<", + ((IArrayTypeSymbol)typeSymbol).ElementType.FullQualifiedName(), ">()"), + MarshalType.SystemArrayOfStringName => source.Append(inputExpr, ".AsSystemArrayOfStringName()"), + MarshalType.SystemArrayOfNodePath => source.Append(inputExpr, ".AsSystemArrayOfNodePath()"), + MarshalType.SystemArrayOfRID => source.Append(inputExpr, ".AsSystemArrayOfRID()"), + MarshalType.Variant => source.Append(inputExpr), + MarshalType.GodotObjectOrDerived => source.Append("(", + typeSymbol.FullQualifiedName(), ")", inputExpr, ".AsGodotObject()"), + MarshalType.StringName => source.Append(inputExpr, ".AsStringName()"), + MarshalType.NodePath => source.Append(inputExpr, ".AsNodePath()"), + MarshalType.RID => source.Append(inputExpr, ".AsRID()"), + MarshalType.GodotDictionary => source.Append(inputExpr, ".AsGodotDictionary()"), + MarshalType.GodotArray => source.Append(inputExpr, ".AsGodotArray()"), + _ => throw new ArgumentOutOfRangeException(nameof(marshalType), marshalType, + "Received unexpected marshal type") + }; + } + + public static StringBuilder AppendManagedToVariantExpr(this StringBuilder source, + string inputExpr, MarshalType marshalType) + { + switch (marshalType) + { + case MarshalType.Boolean: + case MarshalType.Char: + case MarshalType.SByte: + case MarshalType.Int16: + case MarshalType.Int32: + case MarshalType.Int64: + case MarshalType.Byte: + case MarshalType.UInt16: + case MarshalType.UInt32: + case MarshalType.UInt64: + case MarshalType.Single: + case MarshalType.Double: + case MarshalType.String: + case MarshalType.Vector2: + case MarshalType.Vector2i: + case MarshalType.Rect2: + case MarshalType.Rect2i: + case MarshalType.Transform2D: + case MarshalType.Vector3: + case MarshalType.Vector3i: + case MarshalType.Basis: + case MarshalType.Quaternion: + case MarshalType.Transform3D: + case MarshalType.Vector4: + case MarshalType.Vector4i: + case MarshalType.Projection: + case MarshalType.AABB: + case MarshalType.Color: + case MarshalType.Plane: + case MarshalType.Callable: + case MarshalType.SignalInfo: + case MarshalType.ByteArray: + case MarshalType.Int32Array: + case MarshalType.Int64Array: + case MarshalType.Float32Array: + case MarshalType.Float64Array: + case MarshalType.StringArray: + case MarshalType.Vector2Array: + case MarshalType.Vector3Array: + case MarshalType.ColorArray: + case MarshalType.GodotObjectOrDerivedArray: + case MarshalType.SystemArrayOfStringName: + case MarshalType.SystemArrayOfNodePath: + case MarshalType.SystemArrayOfRID: + case MarshalType.GodotObjectOrDerived: + case MarshalType.StringName: + case MarshalType.NodePath: + case MarshalType.RID: + case MarshalType.GodotDictionary: + case MarshalType.GodotArray: + return source.Append("Variant.CreateFrom(", inputExpr, ")"); + case MarshalType.Enum: + return source.Append("Variant.CreateFrom((long)", inputExpr, ")"); + case MarshalType.Variant: + return source.Append(inputExpr); + default: + throw new ArgumentOutOfRangeException(nameof(marshalType), marshalType, + "Received unexpected marshal type"); + } + } } } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs index 8ee9489fe2d..1fdc04a262c 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs @@ -381,7 +381,7 @@ namespace Godot.SourceGenerators if (i != 0) source.Append(", "); - source.AppendVariantToManagedExpr(string.Concat("args[", i.ToString(), "]"), + source.AppendNativeVariantToManagedExpr(string.Concat("args[", i.ToString(), "]"), method.ParamTypeSymbols[i], method.ParamTypes[i]); } @@ -391,7 +391,7 @@ namespace Godot.SourceGenerators { source.Append(" ret = "); - source.AppendManagedToVariantExpr("callRet", method.RetType.Value); + source.AppendManagedToNativeVariantExpr("callRet", method.RetType.Value); source.Append(";\n"); source.Append(" return true;\n"); 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 29a15e2d16a..12a369fd72c 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs @@ -293,7 +293,7 @@ namespace Godot.SourceGenerators .Append(" ") .Append(propertyMemberName) .Append(" = ") - .AppendVariantToManagedExpr("value", propertyTypeSymbol, propertyMarshalType) + .AppendNativeVariantToManagedExpr("value", propertyTypeSymbol, propertyMarshalType) .Append(";\n") .Append(" return true;\n") .Append(" }\n"); @@ -315,7 +315,7 @@ namespace Godot.SourceGenerators .Append(propertyMemberName) .Append(") {\n") .Append(" value = ") - .AppendManagedToVariantExpr(propertyMemberName, propertyMarshalType) + .AppendManagedToNativeVariantExpr(propertyMemberName, propertyMarshalType) .Append(";\n") .Append(" return true;\n") .Append(" }\n"); diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs index 224a2d0a505..1b87c6e7603 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs @@ -160,8 +160,8 @@ namespace Godot.SourceGenerators source.Append(" info.AddProperty(GodotInternal.PropName_") .Append(propertyName) - .Append(", this.") - .Append(propertyName) + .Append(", ") + .AppendManagedToVariantExpr(string.Concat("this.", propertyName), property.Type) .Append(");\n"); } @@ -173,8 +173,8 @@ namespace Godot.SourceGenerators source.Append(" info.AddProperty(GodotInternal.PropName_") .Append(fieldName) - .Append(", this.") - .Append(fieldName) + .Append(", ") + .AppendManagedToVariantExpr(string.Concat("this.", fieldName), field.Type) .Append(");\n"); } @@ -202,19 +202,17 @@ namespace Godot.SourceGenerators foreach (var property in godotClassProperties) { string propertyName = property.PropertySymbol.Name; - string propertyTypeQualifiedName = property.PropertySymbol.Type.FullQualifiedName(); - source.Append(" if (info.TryGetProperty<") - .Append(propertyTypeQualifiedName) - .Append(">(GodotInternal.PropName_") + source.Append(" if (info.TryGetProperty(GodotInternal.PropName_") .Append(propertyName) .Append(", out var _value_") .Append(propertyName) .Append("))\n") .Append(" this.") .Append(propertyName) - .Append(" = _value_") - .Append(propertyName) + .Append(" = ") + .AppendVariantToManagedExpr(string.Concat("_value_", propertyName), + property.PropertySymbol.Type, property.Type) .Append(";\n"); } @@ -223,19 +221,17 @@ namespace Godot.SourceGenerators foreach (var field in godotClassFields) { string fieldName = field.FieldSymbol.Name; - string fieldTypeQualifiedName = field.FieldSymbol.Type.FullQualifiedName(); - source.Append(" if (info.TryGetProperty<") - .Append(fieldTypeQualifiedName) - .Append(">(GodotInternal.PropName_") + source.Append(" if (info.TryGetProperty(GodotInternal.PropName_") .Append(fieldName) .Append(", out var _value_") .Append(fieldName) .Append("))\n") .Append(" this.") .Append(fieldName) - .Append(" = _value_") - .Append(fieldName) + .Append(" = ") + .AppendVariantToManagedExpr(string.Concat("_value_", fieldName), + field.FieldSymbol.Type, field.Type) .Append(";\n"); } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs index 10f4ddd149b..536ddb02f8a 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs @@ -397,7 +397,7 @@ namespace Godot.SourceGenerators if (i != 0) source.Append(", "); - source.AppendVariantToManagedExpr(string.Concat("args[", i.ToString(), "]"), + source.AppendNativeVariantToManagedExpr(string.Concat("args[", i.ToString(), "]"), invokeMethodData.ParamTypeSymbols[i], invokeMethodData.ParamTypes[i]); } diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs index f8a810fd440..3c5b897719a 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs @@ -20,7 +20,7 @@ namespace GodotTools.Build public bool OnlyClean { get; private set; } // TODO Use List once we have proper serialization - public Array CustomProperties { get; private set; } = new Array(); + public Godot.Collections.Array CustomProperties { get; private set; } = new(); public string LogsDirPath => Path.Combine(GodotSharpDirs.BuildLogsDirs, $"{Solution.MD5Text()}_{Configuration}"); diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs index 38d2eefd02a..a8128be9098 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs @@ -1,7 +1,6 @@ using Godot; using System; using System.Diagnostics.CodeAnalysis; -using Godot.Collections; using GodotTools.Internals; using File = GodotTools.Utils.File; using Path = System.IO.Path; @@ -59,7 +58,7 @@ namespace GodotTools.Build } // TODO Use List once we have proper serialization. - private Array _issues = new Array(); + private Godot.Collections.Array _issues = new(); private ItemList _issuesList; private PopupMenu _issuesListContextMenu; private TextEdit _buildLog; @@ -129,12 +128,12 @@ namespace GodotTools.Build if (issueIndex < 0 || issueIndex >= _issues.Count) throw new IndexOutOfRangeException("Issue index out of range"); - BuildIssue issue = _issues[issueIndex]; + var issue = (BuildIssue)_issues[issueIndex]; if (string.IsNullOrEmpty(issue.ProjectFile) && string.IsNullOrEmpty(issue.File)) return; - string projectDir = issue.ProjectFile.Length > 0 ? + string projectDir = !string.IsNullOrEmpty(issue.ProjectFile) ? issue.ProjectFile.GetBaseDir() : _buildInfo.Solution.GetBaseDir(); @@ -163,7 +162,7 @@ namespace GodotTools.Build { for (int i = 0; i < _issues.Count; i++) { - BuildIssue issue = _issues[i]; + var issue = (BuildIssue)_issues[i]; if (!(issue.Warning ? WarningsVisible : ErrorsVisible)) continue; diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs index 506c0ec067c..655be0ab5ec 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs @@ -4,6 +4,7 @@ using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Diagnostics; using System.IO; +using System.Linq; using System.Text; using System.Threading.Tasks; using GodotTools.BuildLogger; @@ -156,9 +157,9 @@ namespace GodotTools.Build AddLoggerArgument(buildInfo, arguments); // Custom properties - foreach (string customProperty in buildInfo.CustomProperties) + foreach (var customProperty in buildInfo.CustomProperties) { - arguments.Add("-p:" + customProperty); + arguments.Add("-p:" + (string)customProperty); } } @@ -198,9 +199,9 @@ namespace GodotTools.Build AddLoggerArgument(buildInfo, arguments); // Custom properties - foreach (string customProperty in buildInfo.CustomProperties) + foreach (var customProperty in buildInfo.CustomProperties) { - arguments.Add("-p:" + customProperty); + arguments.Add("-p:" + (string)customProperty); } // Publish output directory diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index 362bb18b364..dcc3f3db767 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -481,9 +481,9 @@ namespace GodotTools _editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary { - ["type"] = Variant.Type.Int, + ["type"] = (int)Variant.Type.Int, ["name"] = "mono/editor/external_editor", - ["hint"] = PropertyHint.Enum, + ["hint"] = (int)PropertyHint.Enum, ["hint_string"] = settingsHintStr }); diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs index a62fe29e7ec..60602a5847d 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs @@ -30,9 +30,9 @@ namespace GodotTools.Ides.Rider Globals.EditorDef(EditorPathSettingName, "Optional"); editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary { - ["type"] = Variant.Type.String, + ["type"] = (int)Variant.Type.String, ["name"] = EditorPathSettingName, - ["hint"] = PropertyHint.File, + ["hint"] = (int)PropertyHint.File, ["hint_string"] = "" }); } diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 50820c63840..b879c95fa17 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -1664,8 +1664,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str 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 << "(" << sformat(arg_type->cs_variant_to_managed, - "args[" + itos(i) + "]", arg_type->cs_type, arg_type->name) << ")"; + output << "new " << arg_cs_type << "(" << sformat(arg_type->cs_variant_to_managed, "args[" + itos(i) + "]", arg_type->cs_type, arg_type->name) << ")"; } else { output << sformat(arg_type->cs_variant_to_managed, "args[" + itos(i) + "]", arg_type->cs_type, arg_type->name); @@ -2892,8 +2891,13 @@ bool BindingsGenerator::_populate_object_type_interfaces() { String() + "Return type is reference but hint is not '" _STR(PROPERTY_HINT_RESOURCE_TYPE) "'." + " Are you returning a reference type by pointer? Method: '" + itype.name + "." + imethod.name + "'."); } else if (return_info.type == Variant::ARRAY && return_info.hint == PROPERTY_HINT_ARRAY_TYPE) { +// TODO: Enable once generic Array is re-implemented +#if 0 imethod.return_type.cname = Variant::get_type_name(return_info.type) + "_@generic"; imethod.return_type.generic_type_parameters.push_back(TypeReference(return_info.hint_string)); +#else + imethod.return_type.cname = Variant::get_type_name(return_info.type); +#endif } else if (return_info.hint == PROPERTY_HINT_RESOURCE_TYPE) { imethod.return_type.cname = return_info.hint_string; } else if (return_info.type == Variant::NIL && return_info.usage & PROPERTY_USAGE_NIL_IS_VARIANT) { @@ -2924,8 +2928,13 @@ bool BindingsGenerator::_populate_object_type_interfaces() { } else if (arginfo.class_name != StringName()) { iarg.type.cname = arginfo.class_name; } else if (arginfo.type == Variant::ARRAY && arginfo.hint == PROPERTY_HINT_ARRAY_TYPE) { +// TODO: Enable once generic Array is re-implemented +#if 0 iarg.type.cname = Variant::get_type_name(arginfo.type) + "_@generic"; iarg.type.generic_type_parameters.push_back(TypeReference(arginfo.hint_string)); +#else + iarg.type.cname = Variant::get_type_name(arginfo.type); +#endif } else if (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) { iarg.type.cname = arginfo.hint_string; } else if (arginfo.type == Variant::NIL) { @@ -3032,8 +3041,13 @@ bool BindingsGenerator::_populate_object_type_interfaces() { } else if (arginfo.class_name != StringName()) { iarg.type.cname = arginfo.class_name; } else if (arginfo.type == Variant::ARRAY && arginfo.hint == PROPERTY_HINT_ARRAY_TYPE) { +// TODO: Enable once generic Array is re-implemented +#if 0 iarg.type.cname = Variant::get_type_name(arginfo.type) + "_@generic"; iarg.type.generic_type_parameters.push_back(TypeReference(arginfo.hint_string)); +#else + iarg.type.cname = Variant::get_type_name(arginfo.type); +#endif } else if (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) { iarg.type.cname = arginfo.hint_string; } else if (arginfo.type == Variant::NIL) { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs index 8ceb7ea882a..51d7d8195bd 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Collections; -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Godot.NativeInterop; @@ -14,8 +13,8 @@ namespace Godot.Collections /// such as or . /// public sealed class Array : - IList, - IReadOnlyList, + IList, + IReadOnlyList, ICollection, IDisposable { @@ -37,22 +36,90 @@ namespace Godot.Collections /// /// The collection of elements to construct from. /// A new Godot Array. - public Array(IEnumerable collection) : this() + public Array(IEnumerable collection) : this() { if (collection == null) throw new ArgumentNullException(nameof(collection)); - foreach (object element in collection) + foreach (Variant element in collection) Add(element); } - // TODO: This must be removed. Lots of silent mistakes as it takes pretty much anything. /// /// Constructs a new from the given objects. /// /// The objects to put in the new array. /// A new Godot Array. - public Array(params object[] array) : this() + public Array(Variant[] array) : this() + { + if (array == null) + throw new ArgumentNullException(nameof(array)); + + NativeValue = (godot_array.movable)NativeFuncs.godotsharp_array_new(); + _weakReferenceToSelf = DisposablesTracker.RegisterDisposable(this); + + int length = array.Length; + + Resize(length); + + for (int i = 0; i < length; i++) + this[i] = array[i]; + } + + public Array(Span array) : this() + { + if (array == null) + throw new ArgumentNullException(nameof(array)); + + NativeValue = (godot_array.movable)NativeFuncs.godotsharp_array_new(); + _weakReferenceToSelf = DisposablesTracker.RegisterDisposable(this); + + int length = array.Length; + + Resize(length); + + for (int i = 0; i < length; i++) + this[i] = array[i]; + } + + public Array(Span array) : this() + { + if (array == null) + throw new ArgumentNullException(nameof(array)); + + NativeValue = (godot_array.movable)NativeFuncs.godotsharp_array_new(); + _weakReferenceToSelf = DisposablesTracker.RegisterDisposable(this); + + int length = array.Length; + + Resize(length); + + for (int i = 0; i < length; i++) + this[i] = array[i]; + } + + public Array(Span array) : this() + { + if (array == null) + throw new ArgumentNullException(nameof(array)); + + NativeValue = (godot_array.movable)NativeFuncs.godotsharp_array_new(); + _weakReferenceToSelf = DisposablesTracker.RegisterDisposable(this); + + int length = array.Length; + + Resize(length); + + for (int i = 0; i < length; i++) + this[i] = array[i]; + } + + // We must use ReadOnlySpan instead of Span here as this can accept implicit conversions + // from derived types (e.g.: Node[]). Implicit conversion from Derived[] to Base[] are + // fine as long as the array is not mutated. However, Span does this type checking at + // instantiation, so it's not possible to use it even when not mutating anything. + // ReSharper disable once RedundantNameQualifier + public Array(ReadOnlySpan array) : this() { if (array == null) throw new ArgumentNullException(nameof(array)); @@ -170,15 +237,15 @@ namespace Godot.Collections } /// - /// Returns the object at the given . + /// Returns the item at the given . /// - /// The object at the given . - public unsafe object this[int index] + /// The item at the given . + public unsafe Variant this[int index] { get { GetVariantBorrowElementAt(index, out godot_variant borrowElem); - return Marshaling.ConvertVariantToManagedObject(borrowElem); + return Variant.CreateCopyingBorrowed(borrowElem); } set { @@ -186,29 +253,30 @@ namespace Godot.Collections throw new ArgumentOutOfRangeException(nameof(index)); var self = (godot_array)NativeValue; godot_variant* ptrw = NativeFuncs.godotsharp_array_ptrw(ref self); - ptrw[index] = Marshaling.ConvertManagedObjectToVariant(value); + godot_variant* itemPtr = &ptrw[index]; + (*itemPtr).Dispose(); + *itemPtr = value.CopyNativeVariant(); } } /// - /// Adds an object to the end of this . + /// Adds an item to the end of this . /// This is the same as append or push_back in GDScript. /// - /// The object to add. - /// The new size after adding the object. - public void Add(object item) + /// The item to add. + public void Add(Variant item) { - using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(item); + godot_variant variantValue = (godot_variant)item.NativeVar; var self = (godot_array)NativeValue; _ = NativeFuncs.godotsharp_array_add(ref self, variantValue); } /// - /// Checks if this contains the given object. + /// Checks if this contains the given item. /// - /// The item to look for. - /// Whether or not this array contains the given object. - public bool Contains(object item) => IndexOf(item) != -1; + /// The item to look for. + /// Whether or not this array contains the given item. + public bool Contains(Variant item) => IndexOf(item) != -1; /// /// Erases all items from this . @@ -216,32 +284,32 @@ namespace Godot.Collections public void Clear() => Resize(0); /// - /// Searches this for an object + /// Searches this for an item /// and returns its index or -1 if not found. /// - /// The object to search for. - /// The index of the object, or -1 if not found. - public int IndexOf(object item) + /// The item to search for. + /// The index of the item, or -1 if not found. + public int IndexOf(Variant item) { - using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(item); + godot_variant variantValue = (godot_variant)item.NativeVar; var self = (godot_array)NativeValue; return NativeFuncs.godotsharp_array_index_of(ref self, variantValue); } /// - /// Inserts a new object at a given position in the array. + /// Inserts a new item at a given position in the array. /// The position must be a valid position of an existing item, /// or the position at the end of the array. /// Existing items will be moved to the right. /// /// The index to insert at. - /// The object to insert. - public void Insert(int index, object item) + /// The item to insert. + public void Insert(int index, Variant item) { if (index < 0 || index > Count) throw new ArgumentOutOfRangeException(nameof(index)); - using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(item); + godot_variant variantValue = (godot_variant)item.NativeVar; var self = (godot_array)NativeValue; NativeFuncs.godotsharp_array_insert(ref self, index, variantValue); } @@ -251,7 +319,7 @@ namespace Godot.Collections /// from this . /// /// The value to remove. - public bool Remove(object item) + public bool Remove(Variant item) { int index = IndexOf(item); if (index >= 0) @@ -285,19 +353,19 @@ namespace Godot.Collections /// The number of elements. public int Count => NativeValue.DangerousSelfRef.Size; - public bool IsSynchronized => false; + bool ICollection.IsSynchronized => false; - public object SyncRoot => false; + object ICollection.SyncRoot => false; - public bool IsReadOnly => false; + bool ICollection.IsReadOnly => false; /// /// Copies the elements of this to the given - /// untyped C# array, starting at the given index. + /// C# array, starting at the given index. /// /// The array to copy to. /// The index to start at. - public void CopyTo(object[] array, int arrayIndex) + public void CopyTo(Variant[] array, int arrayIndex) { if (array == null) throw new ArgumentNullException(nameof(array), "Value cannot be null."); @@ -320,8 +388,7 @@ namespace Godot.Collections { for (int i = 0; i < count; i++) { - object obj = Marshaling.ConvertVariantToManagedObject(NativeValue.DangerousSelfRef.Elements[i]); - array[arrayIndex] = obj; + array[arrayIndex] = Variant.CreateCopyingBorrowed(NativeValue.DangerousSelfRef.Elements[i]); arrayIndex++; } } @@ -364,37 +431,13 @@ namespace Godot.Collections return Marshaling.ConvertVariantToManagedObjectOfType(borrowElem, type); } - internal void CopyToGeneric(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 /// /// Gets an enumerator for this . /// /// An enumerator. - public IEnumerator GetEnumerator() + public IEnumerator GetEnumerator() { int count = Count; @@ -436,289 +479,4 @@ namespace Godot.Collections elem = NativeValue.DangerousSelfRef.Elements[index]; } } - - internal interface IGenericGodotArray - { - Array UnderlyingArray { get; } - Type TypeOfElements { get; } - } - - // TODO: Now we should be able to avoid boxing - /// - /// Typed wrapper around Godot's Array class, an array of Variant - /// typed elements allocated in the engine in C++. Useful when - /// interfacing with the engine. Otherwise prefer .NET collections - /// such as arrays or . - /// - /// The type of the array. - [SuppressMessage("ReSharper", "RedundantExtendsListEntry")] - [SuppressMessage("Naming", "CA1710", MessageId = "Identifiers should have correct suffix")] - public sealed class Array : IList, ICollection, IEnumerable, IGenericGodotArray - { - private readonly Array _underlyingArray; - - internal ref godot_array.movable NativeValue - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => ref _underlyingArray.NativeValue; - } - - // ReSharper disable StaticMemberInGenericType - // Warning is about unique static fields being created for each generic type combination: - // https://www.jetbrains.com/help/resharper/StaticMemberInGenericType.html - // In our case this is exactly what we want. - private static readonly Type TypeOfElements = typeof(T); - // ReSharper restore StaticMemberInGenericType - - Array IGenericGodotArray.UnderlyingArray => _underlyingArray; - Type IGenericGodotArray.TypeOfElements => TypeOfElements; - - /// - /// Constructs a new empty . - /// - public Array() - { - _underlyingArray = new Array(); - } - - /// - /// Constructs a new from the given collection's elements. - /// - /// The collection of elements to construct from. - /// A new Godot Array. - public Array(IEnumerable collection) - { - if (collection == null) - throw new ArgumentNullException(nameof(collection)); - - _underlyingArray = new Array(collection); - } - - /// - /// Constructs a new from the given items. - /// - /// The items to put in the new array. - /// A new Godot Array. - public Array(params T[] array) : this() - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - - _underlyingArray = new Array(array); - } - - /// - /// Constructs a typed from an untyped . - /// - /// The untyped array to construct from. - public Array(Array array) - { - _underlyingArray = array; - } - - // Explicit name to make it very clear - internal static Array CreateTakingOwnershipOfDisposableValue(godot_array nativeValueToOwn) - => new Array(Array.CreateTakingOwnershipOfDisposableValue(nativeValueToOwn)); - - /// - /// Converts this typed to an untyped . - /// - /// The typed array to convert. - public static explicit operator Array(Array from) - { - return from?._underlyingArray; - } - - /// - /// Duplicates this . - /// - /// If , performs a deep copy. - /// A new Godot Array. - public Array Duplicate(bool deep = false) - { - return new Array(_underlyingArray.Duplicate(deep)); - } - - /// - /// Resizes this to the given size. - /// - /// The new size of the array. - /// if successful, or an error code. - public Error Resize(int newSize) - { - return _underlyingArray.Resize(newSize); - } - - /// - /// Shuffles the contents of this into a random order. - /// - public void Shuffle() - { - _underlyingArray.Shuffle(); - } - - /// - /// Concatenates these two s. - /// - /// The first array. - /// The second array. - /// A new Godot Array with the contents of both arrays. - public static Array operator +(Array left, Array right) - { - if (left == null) - { - if (right == null) - return new Array(); - - return right.Duplicate(deep: false); - } - - if (right == null) - return left.Duplicate(deep: false); - - return new Array(left._underlyingArray + right._underlyingArray); - } - - // IList - - /// - /// Returns the value at the given . - /// - /// The value at the given . - public T this[int index] - { - get => (T)_underlyingArray.GetAtAsType(index, TypeOfElements); - set => _underlyingArray[index] = value; - } - - /// - /// Searches this for an item - /// and returns its index or -1 if not found. - /// - /// The item to search for. - /// The index of the item, or -1 if not found. - public int IndexOf(T item) - { - return _underlyingArray.IndexOf(item); - } - - /// - /// Inserts a new item at a given position in the . - /// The position must be a valid position of an existing item, - /// or the position at the end of the array. - /// Existing items will be moved to the right. - /// - /// The index to insert at. - /// The item to insert. - public void Insert(int index, T item) - { - _underlyingArray.Insert(index, item); - } - - /// - /// Removes an element from this by index. - /// - /// The index of the element to remove. - public void RemoveAt(int index) - { - _underlyingArray.RemoveAt(index); - } - - // ICollection - - /// - /// Returns the number of elements in this . - /// This is also known as the size or length of the array. - /// - /// The number of elements. - public int Count => _underlyingArray.Count; - - bool ICollection.IsReadOnly => false; - - /// - /// Adds an item to the end of this . - /// This is the same as append or push_back in GDScript. - /// - /// The item to add. - /// The new size after adding the item. - public void Add(T item) - { - _underlyingArray.Add(item); - } - - /// - /// Erases all items from this . - /// - public void Clear() - { - _underlyingArray.Clear(); - } - - /// - /// Checks if this contains the given item. - /// - /// The item to look for. - /// Whether or not this array contains the given item. - public bool Contains(T item) - { - return _underlyingArray.Contains(item); - } - - /// - /// Copies the elements of this to the given - /// C# array, starting at the given index. - /// - /// The C# array to copy to. - /// The index to start at. - public void CopyTo(T[] array, int arrayIndex) => - _underlyingArray.CopyToGeneric(array, arrayIndex, TypeOfElements); - - /// - /// Removes the first occurrence of the specified value - /// from this . - /// - /// The value to remove. - /// A indicating success or failure. - public bool Remove(T item) - { - int index = IndexOf(item); - if (index >= 0) - { - RemoveAt(index); - return true; - } - - return false; - } - - // IEnumerable - - /// - /// Gets an enumerator for this . - /// - /// An enumerator. - public IEnumerator GetEnumerator() - { - int count = _underlyingArray.Count; - - for (int i = 0; i < count; i++) - { - yield return this[i]; - } - } - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - /// - /// Converts this to a string. - /// - /// A string representation of this array. - public override string ToString() => _underlyingArray.ToString(); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Variant(Array from) => Variant.From(from); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static explicit operator Array(Variant from) => from.AsGodotGenericArray(); - } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs index 3636a08377e..ae44f8f4ba4 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs @@ -206,11 +206,8 @@ namespace Godot.Bridge // Save instance state - var info = new GodotSerializationInfo( - Collections.Dictionary.CreateTakingOwnershipOfDisposableValue( - NativeFuncs.godotsharp_dictionary_new_copy(*propertiesState)), - Collections.Dictionary.CreateTakingOwnershipOfDisposableValue( - NativeFuncs.godotsharp_dictionary_new_copy(*signalEventsState))); + using var info = GodotSerializationInfo.CreateCopyingBorrowed( + *propertiesState, *signalEventsState); godotObject.SaveGodotObjectData(info); } @@ -236,11 +233,8 @@ namespace Godot.Bridge // Restore instance state - var info = new GodotSerializationInfo( - Collections.Dictionary.CreateTakingOwnershipOfDisposableValue( - NativeFuncs.godotsharp_dictionary_new_copy(*propertiesState)), - Collections.Dictionary.CreateTakingOwnershipOfDisposableValue( - NativeFuncs.godotsharp_dictionary_new_copy(*signalEventsState))); + using var info = GodotSerializationInfo.CreateCopyingBorrowed( + *propertiesState, *signalEventsState); godotObject.RestoreGodotObjectData(info); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GodotSerializationInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GodotSerializationInfo.cs index 53aeff8207b..8f26967dcd0 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GodotSerializationInfo.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GodotSerializationInfo.cs @@ -1,35 +1,43 @@ using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using Godot.NativeInterop; namespace Godot.Bridge; -public class GodotSerializationInfo +public class GodotSerializationInfo : IDisposable { - private readonly Collections.Dictionary _properties = new(); - private readonly Collections.Dictionary _signalEvents = new(); + private readonly Collections.Dictionary _properties; + private readonly Collections.Dictionary _signalEvents; - internal GodotSerializationInfo() + public void Dispose() { + _properties?.Dispose(); + _signalEvents?.Dispose(); + + GC.SuppressFinalize(this); } - internal GodotSerializationInfo( - Collections.Dictionary properties, - Collections.Dictionary signalEvents - ) + private GodotSerializationInfo(in godot_dictionary properties, in godot_dictionary signalEvents) { - _properties = properties; - _signalEvents = signalEvents; + _properties = Collections.Dictionary.CreateTakingOwnershipOfDisposableValue(properties); + _signalEvents = Collections.Dictionary.CreateTakingOwnershipOfDisposableValue(signalEvents); } - public void AddProperty(StringName name, object value) + internal static GodotSerializationInfo CreateCopyingBorrowed( + in godot_dictionary properties, in godot_dictionary signalEvents) + { + return new(NativeFuncs.godotsharp_dictionary_new_copy(properties), + NativeFuncs.godotsharp_dictionary_new_copy(signalEvents)); + } + + public void AddProperty(StringName name, Variant value) { _properties[name] = value; } - public bool TryGetProperty(StringName name, [MaybeNullWhen(false)] out T value) + public bool TryGetProperty(StringName name, out Variant value) { - return _properties.TryGetValueAsType(name, out value); + return _properties.TryGetValue(name, out value); } public void AddSignalEventDelegate(StringName name, Delegate eventDelegate) @@ -49,9 +57,9 @@ public class GodotSerializationInfo public bool TryGetSignalEventDelegate(StringName name, [MaybeNullWhen(false)] out T value) where T : Delegate { - if (_signalEvents.TryGetValue(name, out Collections.Array serializedData)) + if (_signalEvents.TryGetValue(name, out Variant serializedData)) { - if (DelegateUtils.TryDeserializeDelegate(serializedData, out var eventDelegate)) + if (DelegateUtils.TryDeserializeDelegate(serializedData.AsGodotArray(), out var eventDelegate)) { value = eventDelegate as T; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/MethodInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/MethodInfo.cs index 50260163bd6..647ae436ffb 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/MethodInfo.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/MethodInfo.cs @@ -11,10 +11,10 @@ public struct MethodInfo public MethodFlags Flags { get; init; } public int Id { get; init; } = 0; public List? Arguments { get; init; } - public List? DefaultArguments { get; init; } + public List? DefaultArguments { get; init; } - public MethodInfo(StringName name, PropertyInfo returnVal, MethodFlags flags, List? arguments, - List? defaultArguments) + public MethodInfo(StringName name, PropertyInfo returnVal, MethodFlags flags, + List? arguments, List? defaultArguments) { Name = name; ReturnVal = returnVal; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs index 03094cbe81b..0dc5ba7678f 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs @@ -608,8 +608,8 @@ namespace Godot.Bridge methodParams.Add(new Collections.Dictionary() { { "name", param.Name }, - { "type", param.Type }, - { "usage", param.Usage } + { "type", (int)param.Type }, + { "usage", (int)param.Usage } }); } } @@ -628,7 +628,7 @@ namespace Godot.Bridge // RPC functions - Collections.Dictionary rpcFunctions = new(); + Collections.Dictionary rpcFunctions = new(); top = scriptType; @@ -665,7 +665,7 @@ namespace Godot.Bridge } *outRpcFunctionsDest = NativeFuncs.godotsharp_dictionary_new_copy( - (godot_dictionary)((Collections.Dictionary)rpcFunctions).NativeValue); + (godot_dictionary)(rpcFunctions).NativeValue); // Event signals @@ -696,8 +696,8 @@ namespace Godot.Bridge signalParams.Add(new Collections.Dictionary() { { "name", param.Name }, - { "type", param.Type }, - { "usage", param.Usage } + { "type", (int)param.Type }, + { "usage", (int)param.Usage } }); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs index ef75ff446ac..8d0e77d1712 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs @@ -85,7 +85,7 @@ namespace Godot /// /// Arguments that will be passed to the method call. /// The value returned by the method. - public unsafe object Call(params object[] args) + public unsafe Variant Call(params Variant[] args) { using godot_callable callable = Marshaling.ConvertCallableToNative(this); @@ -106,13 +106,13 @@ namespace Godot { for (int i = 0; i < argc; i++) { - varargs[i] = Marshaling.ConvertManagedObjectToVariant(args[i]); + varargs[i] = (godot_variant)args[i].NativeVar; argsPtr[i] = new IntPtr(&varargs[i]); } - using godot_variant ret = NativeFuncs.godotsharp_callable_call(callable, + godot_variant ret = NativeFuncs.godotsharp_callable_call(callable, (godot_variant**)argsPtr, argc, out _); - return Marshaling.ConvertVariantToManagedObject(ret); + return Variant.CreateTakingOwnershipOfDisposableValue(ret); } } @@ -121,7 +121,7 @@ namespace Godot /// Arguments can be passed and should match the method's signature. /// /// Arguments that will be passed to the method call. - public unsafe void CallDeferred(params object[] args) + public unsafe void CallDeferred(params Variant[] args) { using godot_callable callable = Marshaling.ConvertCallableToNative(this); @@ -142,7 +142,7 @@ namespace Godot { for (int i = 0; i < argc; i++) { - varargs[i] = Marshaling.ConvertManagedObjectToVariant(args[i]); + varargs[i] = (godot_variant)args[i].NativeVar; argsPtr[i] = new IntPtr(&varargs[i]); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs index 48eec661822..266038a0afb 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs @@ -99,7 +99,7 @@ namespace Godot if (TrySerializeSingleDelegate(@delegate, out byte[]? buffer)) { - serializedData.Add(buffer); + serializedData.Add((Span)buffer); return true; } @@ -181,8 +181,18 @@ namespace Godot if (variantType == Variant.Type.Nil) return false; + static byte[] Var2Bytes(in godot_variant var) + { + NativeFuncs.godotsharp_var2bytes(var, false.ToGodotBool(), out var varBytes); + using (varBytes) + return Marshaling.ConvertNativePackedByteArrayToSystemArray(varBytes); + } + writer.Write(field.Name); - byte[] valueBuffer = GD.Var2Bytes(field.GetValue(target)); + + var fieldValue = field.GetValue(target); + using var fieldValueVariant = Marshaling.ConvertManagedObjectToVariant(fieldValue); + byte[] valueBuffer = Var2Bytes(fieldValueVariant); writer.Write(valueBuffer.Length); writer.Write(valueBuffer); } @@ -320,9 +330,14 @@ namespace Godot internal static bool TryDeserializeDelegate(Collections.Array serializedData, [MaybeNullWhen(false)] out Delegate @delegate) { + @delegate = null; + if (serializedData.Count == 1) { - object elem = serializedData[0]; + var elem = serializedData[0].Obj; + + if (elem == null) + return false; if (elem is Collections.Array multiCastData) return TryDeserializeDelegate(multiCastData, out @delegate); @@ -330,12 +345,15 @@ namespace Godot return TryDeserializeSingleDelegate((byte[])elem, out @delegate); } - @delegate = null; - var delegates = new List(serializedData.Count); - foreach (object elem in serializedData) + foreach (Variant variantElem in serializedData) { + var elem = variantElem.Obj; + + if (elem == null) + continue; + if (elem is Collections.Array multiCastData) { if (TryDeserializeDelegate(multiCastData, out Delegate? oneDelegate)) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs index a71ee1190ee..c3d500119aa 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs @@ -2,10 +2,6 @@ using System; using System.Collections.Generic; using System.Collections; using Godot.NativeInterop; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; -using System.Linq; -using System.Runtime.CompilerServices; namespace Godot.Collections { @@ -15,9 +11,8 @@ namespace Godot.Collections /// interfacing with the engine. /// public sealed class Dictionary : - IDictionary, - IDictionary, - IReadOnlyDictionary, + IDictionary, + IReadOnlyDictionary, IDisposable { internal godot_dictionary.movable NativeValue; @@ -33,20 +28,6 @@ namespace Godot.Collections _weakReferenceToSelf = DisposablesTracker.RegisterDisposable(this); } - /// - /// Constructs a new from the given dictionary's elements. - /// - /// The dictionary to construct from. - /// A new Godot Dictionary. - public Dictionary(IDictionary dictionary) : this() - { - if (dictionary == null) - throw new ArgumentNullException(nameof(dictionary)); - - foreach (DictionaryEntry entry in dictionary) - Add(entry.Key, entry.Value); - } - private Dictionary(godot_dictionary nativeValueToOwn) { NativeValue = (godot_dictionary.movable)(nativeValueToOwn.IsAllocated ? @@ -102,7 +83,7 @@ namespace Godot.Collections /// /// Gets the collection of keys in this . /// - public ICollection Keys + public ICollection Keys { get { @@ -116,7 +97,7 @@ namespace Godot.Collections /// /// Gets the collection of elements in this . /// - public ICollection Values + public ICollection Values { get { @@ -127,13 +108,9 @@ namespace Godot.Collections } } - IEnumerable IReadOnlyDictionary.Keys => Keys; + IEnumerable IReadOnlyDictionary.Keys => Keys; - IEnumerable IReadOnlyDictionary.Values => Values; - - ICollection IDictionary.Keys => Keys.ToList(); - - ICollection IDictionary.Values => Values.ToList(); + IEnumerable IReadOnlyDictionary.Values => Values; private (Array keys, Array values, int count) GetKeyValuePairs() { @@ -152,25 +129,20 @@ namespace Godot.Collections return (keys, values, count); } - bool IDictionary.IsFixedSize => false; - - bool IDictionary.IsReadOnly => false; - /// - /// Returns the object at the given . + /// Returns the value at the given . /// - /// The object at the given . - public object this[object key] + /// The value at the given . + public Variant this[Variant key] { get { - using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); var self = (godot_dictionary)NativeValue; - if (NativeFuncs.godotsharp_dictionary_try_get_value(ref self, variantKey, - out godot_variant value).ToBool()) + + if (NativeFuncs.godotsharp_dictionary_try_get_value(ref self, + (godot_variant)key.NativeVar, out godot_variant value).ToBool()) { - using (value) - return Marshaling.ConvertVariantToManagedObject(value); + return Variant.CreateTakingOwnershipOfDisposableValue(value); } else { @@ -179,33 +151,31 @@ namespace Godot.Collections } set { - using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); - using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(value); var self = (godot_dictionary)NativeValue; - NativeFuncs.godotsharp_dictionary_set_value(ref self, variantKey, variantValue); + NativeFuncs.godotsharp_dictionary_set_value(ref self, + (godot_variant)key.NativeVar, (godot_variant)value.NativeVar); } } /// - /// Adds an object at key + /// Adds an value at key /// to this . /// - /// The key at which to add the object. - /// The object to add. - public void Add(object key, object value) + /// The key at which to add the value. + /// The value to add. + public void Add(Variant key, Variant value) { - using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); - + var variantKey = (godot_variant)key.NativeVar; var self = (godot_dictionary)NativeValue; if (NativeFuncs.godotsharp_dictionary_contains_key(ref self, variantKey).ToBool()) throw new ArgumentException("An element with the same key already exists", nameof(key)); - using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(value); + godot_variant variantValue = (godot_variant)value.NativeVar; NativeFuncs.godotsharp_dictionary_add(ref self, variantKey, variantValue); } - void ICollection>.Add(KeyValuePair item) + void ICollection>.Add(KeyValuePair item) => Add(item.Key, item.Value); /// @@ -222,16 +192,15 @@ namespace Godot.Collections /// /// The key to look for. /// Whether or not this dictionary contains the given key. - public bool ContainsKey(object key) + public bool ContainsKey(Variant key) { - using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); var self = (godot_dictionary)NativeValue; - return NativeFuncs.godotsharp_dictionary_contains_key(ref self, variantKey).ToBool(); + return NativeFuncs.godotsharp_dictionary_contains_key(ref self, (godot_variant)key.NativeVar).ToBool(); } - public bool Contains(KeyValuePair item) + public bool Contains(KeyValuePair item) { - using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(item.Key); + godot_variant variantKey = (godot_variant)item.Key.NativeVar; var self = (godot_dictionary)NativeValue; bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self, variantKey, out godot_variant retValue).ToBool(); @@ -241,30 +210,24 @@ namespace Godot.Collections if (!found) return false; - using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(item.Value); + godot_variant variantValue = (godot_variant)item.Value.NativeVar; return NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool(); } } - bool IDictionary.Contains(object key) - { - throw new NotImplementedException(); - } - /// /// Removes an element from this by key. /// /// The key of the element to remove. - public bool Remove(object key) + public bool Remove(Variant key) { - using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); var self = (godot_dictionary)NativeValue; - return NativeFuncs.godotsharp_dictionary_remove_key(ref self, variantKey).ToBool(); + return NativeFuncs.godotsharp_dictionary_remove_key(ref self, (godot_variant)key.NativeVar).ToBool(); } - public bool Remove(KeyValuePair item) + public bool Remove(KeyValuePair item) { - using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(item.Key); + godot_variant variantKey = (godot_variant)item.Key.NativeVar; var self = (godot_dictionary)NativeValue; bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self, variantKey, out godot_variant retValue).ToBool(); @@ -274,7 +237,7 @@ namespace Godot.Collections if (!found) return false; - using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(item.Value); + godot_variant variantValue = (godot_variant)item.Value.NativeVar; if (NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool()) { return NativeFuncs.godotsharp_dictionary_remove_key( @@ -285,17 +248,6 @@ namespace Godot.Collections } } - void IDictionary.Remove(object key) - { - _ = Remove(key); - } - - // ICollection - - object ICollection.SyncRoot => this; - - bool ICollection.IsSynchronized => false; - /// /// Returns the number of elements in this . /// This is also known as the size or length of the dictionary. @@ -310,19 +262,15 @@ namespace Godot.Collections } } - public bool IsReadOnly => false; + bool ICollection>.IsReadOnly => false; - public bool TryGetValue(object key, out object value) + public bool TryGetValue(Variant key, out Variant value) { - using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); var self = (godot_dictionary)NativeValue; bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self, - variantKey, out godot_variant retValue).ToBool(); + (godot_variant)key.NativeVar, out godot_variant retValue).ToBool(); - using (retValue) - { - value = found ? Marshaling.ConvertVariantToManagedObject(retValue) : default; - } + value = found ? Variant.CreateTakingOwnershipOfDisposableValue(retValue) : default; return found; } @@ -333,7 +281,7 @@ namespace Godot.Collections /// /// The array to copy to. /// The index to start at. - public void CopyTo(KeyValuePair[] array, int arrayIndex) + public void CopyTo(KeyValuePair[] array, int arrayIndex) { if (array == null) throw new ArgumentNullException(nameof(array), "Value cannot be null."); @@ -355,35 +303,13 @@ namespace Godot.Collections } } - void ICollection.CopyTo(System.Array 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."); - - var (keys, values, count) = GetKeyValuePairs(); - - 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.SetValue(new DictionaryEntry(keys[i], values[i]), arrayIndex); - arrayIndex++; - } - } - // IEnumerable /// /// Gets an enumerator for this . /// /// An enumerator. - public IEnumerator> GetEnumerator() + public IEnumerator> GetEnumerator() { for (int i = 0; i < Count; i++) { @@ -393,84 +319,14 @@ namespace Godot.Collections IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - IDictionaryEnumerator IDictionary.GetEnumerator() => new DictionaryEnumerator(this); - - private class DictionaryEnumerator : IDictionaryEnumerator - { - private readonly Dictionary _dictionary; - private readonly int _count; - private int _index = -1; - private bool _dirty = true; - - private DictionaryEntry _entry; - - public DictionaryEnumerator(Dictionary dictionary) - { - _dictionary = dictionary; - _count = dictionary.Count; - } - - public object Current => Entry; - - public DictionaryEntry Entry - { - get - { - if (_dirty) - { - UpdateEntry(); - } - - return _entry; - } - } - - private void UpdateEntry() - { - _dirty = false; - var self = (godot_dictionary)_dictionary.NativeValue; - NativeFuncs.godotsharp_dictionary_key_value_pair_at(ref self, _index, - out godot_variant key, - out godot_variant value); - using (key) - using (value) - { - // FIXME: DictionaryEntry keys cannot be null, but Godot dictionaries allow null keys - _entry = new DictionaryEntry(Marshaling.ConvertVariantToManagedObject(key)!, - Marshaling.ConvertVariantToManagedObject(value)); - } - } - - public object Key => Entry.Key; - - public object Value => Entry.Value; - - public bool MoveNext() - { - _index++; - _dirty = true; - return _index < _count; - } - - public void Reset() - { - _index = -1; - _dirty = true; - } - } - - private KeyValuePair GetKeyValuePair(int index) + private KeyValuePair GetKeyValuePair(int index) { var self = (godot_dictionary)NativeValue; NativeFuncs.godotsharp_dictionary_key_value_pair_at(ref self, index, out godot_variant key, out godot_variant value); - using (key) - using (value) - { - return new KeyValuePair(Marshaling.ConvertVariantToManagedObject(key), - Marshaling.ConvertVariantToManagedObject(value)); - } + return new KeyValuePair(Variant.CreateTakingOwnershipOfDisposableValue(key), + Variant.CreateTakingOwnershipOfDisposableValue(value)); } /// @@ -485,332 +341,4 @@ namespace Godot.Collections return Marshaling.ConvertStringToManaged(str); } } - - internal interface IGenericGodotDictionary - { - Dictionary UnderlyingDictionary { get; } - Type TypeOfKeys { get; } - Type TypeOfValues { get; } - } - - // TODO: Now we should be able to avoid boxing - - /// - /// Typed wrapper around Godot's Dictionary class, a dictionary of Variant - /// typed elements allocated in the engine in C++. Useful when - /// interfacing with the engine. Otherwise prefer .NET collections - /// such as . - /// - /// The type of the dictionary's keys. - /// The type of the dictionary's values. - public class Dictionary : - IDictionary, IGenericGodotDictionary - { - private readonly Dictionary _underlyingDict; - - internal ref godot_dictionary.movable NativeValue - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => ref _underlyingDict.NativeValue; - } - - // ReSharper disable StaticMemberInGenericType - // Warning is about unique static fields being created for each generic type combination: - // https://www.jetbrains.com/help/resharper/StaticMemberInGenericType.html - // In our case this is exactly what we want. - private static readonly Type TypeOfKeys = typeof(TKey); - - private static readonly Type TypeOfValues = typeof(TValue); - // ReSharper restore StaticMemberInGenericType - - Dictionary IGenericGodotDictionary.UnderlyingDictionary => _underlyingDict; - Type IGenericGodotDictionary.TypeOfKeys => TypeOfKeys; - Type IGenericGodotDictionary.TypeOfValues => TypeOfValues; - - /// - /// Constructs a new empty . - /// - public Dictionary() - { - _underlyingDict = new Dictionary(); - } - - /// - /// Constructs a new from the given dictionary's elements. - /// - /// The dictionary to construct from. - /// A new Godot Dictionary. - public Dictionary(IDictionary dictionary) - { - if (dictionary == null) - throw new ArgumentNullException(nameof(dictionary)); - - _underlyingDict = new Dictionary(); - - foreach (KeyValuePair entry in dictionary) - Add(entry.Key, entry.Value); - } - - /// - /// Constructs a new from the given dictionary's elements. - /// - /// The dictionary to construct from. - /// A new Godot Dictionary. - public Dictionary(Dictionary dictionary) - { - _underlyingDict = dictionary; - } - - // Explicit name to make it very clear - internal static Dictionary CreateTakingOwnershipOfDisposableValue( - godot_dictionary nativeValueToOwn) - => new Dictionary(Dictionary.CreateTakingOwnershipOfDisposableValue(nativeValueToOwn)); - - /// - /// Converts this typed to an untyped . - /// - /// The typed dictionary to convert. - public static explicit operator Dictionary(Dictionary from) - { - return from?._underlyingDict; - } - - /// - /// Duplicates this . - /// - /// If , performs a deep copy. - /// A new Godot Dictionary. - public Dictionary Duplicate(bool deep = false) - { - return new Dictionary(_underlyingDict.Duplicate(deep)); - } - - // IDictionary - - /// - /// Returns the value at the given . - /// - /// The value at the given . - public TValue this[TKey key] - { - get - { - using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); - var self = (godot_dictionary)_underlyingDict.NativeValue; - if (NativeFuncs.godotsharp_dictionary_try_get_value(ref self, - variantKey, out godot_variant value).ToBool()) - { - using (value) - return (TValue)Marshaling.ConvertVariantToManagedObjectOfType(value, TypeOfValues); - } - else - { - throw new KeyNotFoundException(); - } - } - set => _underlyingDict[key] = value; - } - - /// - /// Gets the collection of keys in this . - /// - public ICollection Keys - { - get - { - godot_array keyArray; - var self = (godot_dictionary)_underlyingDict.NativeValue; - NativeFuncs.godotsharp_dictionary_keys(ref self, out keyArray); - return Array.CreateTakingOwnershipOfDisposableValue(keyArray); - } - } - - /// - /// Gets the collection of elements in this . - /// - public ICollection Values - { - get - { - godot_array valuesArray; - var self = (godot_dictionary)_underlyingDict.NativeValue; - NativeFuncs.godotsharp_dictionary_values(ref self, out valuesArray); - return Array.CreateTakingOwnershipOfDisposableValue(valuesArray); - } - } - - private KeyValuePair GetKeyValuePair(int index) - { - var self = (godot_dictionary)_underlyingDict.NativeValue; - NativeFuncs.godotsharp_dictionary_key_value_pair_at(ref self, index, - out godot_variant key, - out godot_variant value); - using (key) - using (value) - { - return new KeyValuePair( - (TKey)Marshaling.ConvertVariantToManagedObjectOfType(key, TypeOfKeys), - (TValue)Marshaling.ConvertVariantToManagedObjectOfType(value, TypeOfValues)); - } - } - - /// - /// Adds an object at key - /// to this . - /// - /// The key at which to add the object. - /// The object to add. - public void Add(TKey key, TValue value) - { - _underlyingDict.Add(key, value); - } - - /// - /// Checks if this contains the given key. - /// - /// The key to look for. - /// Whether or not this dictionary contains the given key. - public bool ContainsKey(TKey key) - { - return _underlyingDict.ContainsKey(key); - } - - /// - /// Removes an element from this by key. - /// - /// The key of the element to remove. - public bool Remove(TKey key) - { - using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); - var self = (godot_dictionary)_underlyingDict.NativeValue; - return NativeFuncs.godotsharp_dictionary_remove_key(ref self, variantKey).ToBool(); - } - - /// - /// Gets the object at the given . - /// - /// The key of the element to get. - /// The value at the given . - /// If an object was found for the given . - public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) - { - using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); - var self = (godot_dictionary)_underlyingDict.NativeValue; - bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self, - variantKey, out godot_variant retValue).ToBool(); - - using (retValue) - { - value = found ? - (TValue)Marshaling.ConvertVariantToManagedObjectOfType(retValue, TypeOfValues) : - default; - } - - return found; - } - - // TODO: This is temporary. It's needed for the serialization generator. It won't be needed once we replace System.Object with a Variant type. - internal bool TryGetValueAsType(TKey key, [MaybeNullWhen(false)] out TValueCustom value) - { - using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); - var self = (godot_dictionary)_underlyingDict.NativeValue; - bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self, - variantKey, out godot_variant retValue).ToBool(); - - using (retValue) - { - value = found ? - (TValueCustom)Marshaling.ConvertVariantToManagedObjectOfType(retValue, typeof(TValueCustom)) : - default; - } - - return found; - } - - // ICollection> - - /// - /// Returns the number of elements in this . - /// This is also known as the size or length of the dictionary. - /// - /// The number of elements. - public int Count => _underlyingDict.Count; - - bool ICollection>.IsReadOnly => false; - - void ICollection>.Add(KeyValuePair item) - { - _underlyingDict.Add(item.Key, item.Value); - } - - /// - /// Erases all the items from this . - /// - public void Clear() - { - _underlyingDict.Clear(); - } - - bool ICollection>.Contains(KeyValuePair item) - => _underlyingDict.Contains(new(item.Key, item.Value)); - - /// - /// Copies the elements of this to the given - /// untyped C# array, starting at the given index. - /// - /// The array to copy to. - /// The index to start at. - public void CopyTo(KeyValuePair[] 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 = 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] = GetKeyValuePair(i); - arrayIndex++; - } - } - - bool ICollection>.Remove(KeyValuePair item) - => _underlyingDict.Remove(new(item.Key, item.Value)); - - // IEnumerable> - - /// - /// Gets an enumerator for this . - /// - /// An enumerator. - public IEnumerator> GetEnumerator() - { - for (int i = 0; i < Count; i++) - { - yield return GetKeyValuePair(i); - } - } - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - /// - /// Converts this to a string. - /// - /// A string representation of this dictionary. - public override string ToString() => _underlyingDict.ToString(); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Variant(Dictionary from) => Variant.From(from); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static explicit operator Dictionary(Variant from) => from.AsGodotGenericDictionary(); - } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs deleted file mode 100644 index fa8a1c64029..00000000000 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System.Reflection; -using Godot.Collections; -using Godot.NativeInterop; - -namespace Godot -{ - public partial class SceneTree - { - /// - /// Returns a list of all nodes assigned to the given . - /// - /// The type to cast to. Should be a descendant of . - public Array GetNodesInGroup(StringName group) where T : class - { - var array = GetNodesInGroup(group); - - if (array.Count == 0) - return new Array(array); - - var typeOfT = typeof(T); - bool nativeBase = InternalIsClassNativeBase(typeOfT); - - if (nativeBase) - { - // Native type - var field = typeOfT.GetField("NativeName", - BindingFlags.DeclaredOnly | BindingFlags.Static | - BindingFlags.Public | BindingFlags.NonPublic); - - var nativeName = (StringName)field!.GetValue(null); - var nativeNameSelf = (godot_string_name)nativeName!.NativeValue; - var inputSelf = (godot_array)array.NativeValue; - NativeFuncs.godotsharp_array_filter_godot_objects_by_native(nativeNameSelf, inputSelf, - out godot_array filteredArray); - return Array.CreateTakingOwnershipOfDisposableValue(filteredArray); - } - else - { - // Custom derived type - var inputSelf = (godot_array)array.NativeValue; - NativeFuncs.godotsharp_array_filter_godot_objects_by_non_native(inputSelf, - out godot_array filteredArray); - - var filteredArrayWrapped = Array.CreateTakingOwnershipOfDisposableValue(filteredArray); - - // Re-use first array as its size is the same or greater than the filtered one - var resWrapped = new Array(array); - - int j = 0; - for (int i = 0; i < filteredArrayWrapped.Count; i++) - { - if (filteredArrayWrapped[i] is T t) - { - resWrapped[j] = t; - j++; - } - } - - // Remove trailing elements, since this was re-used - resWrapped.Resize(j); - - return resWrapped; - } - } - } -} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs index 206a8f1c0ad..9348cc1d003 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs @@ -21,12 +21,11 @@ namespace Godot /// Byte array that will be decoded to a Variant. /// If objects should be decoded. /// The decoded Variant. - public static object Bytes2Var(byte[] bytes, bool allowObjects = false) + public static Variant Bytes2Var(Span bytes, bool allowObjects = false) { using var varBytes = Marshaling.ConvertSystemArrayToNativePackedByteArray(bytes); NativeFuncs.godotsharp_bytes2var(varBytes, allowObjects.ToGodotBool(), out godot_variant ret); - using (ret) - return Marshaling.ConvertVariantToManagedObject(ret); + return Variant.CreateTakingOwnershipOfDisposableValue(ret); } /// @@ -44,12 +43,10 @@ namespace Godot /// /// /// The Variant converted to the given . - public static object Convert(object what, Variant.Type type) + public static Variant Convert(Variant what, Variant.Type type) { - using var whatVariant = Marshaling.ConvertManagedObjectToVariant(what); - NativeFuncs.godotsharp_convert(whatVariant, (int)type, out godot_variant ret); - using (ret) - return Marshaling.ConvertVariantToManagedObject(ret); + NativeFuncs.godotsharp_convert((godot_variant)what.NativeVar, (int)type, out godot_variant ret); + return Variant.CreateTakingOwnershipOfDisposableValue(ret); } /// @@ -83,10 +80,9 @@ namespace Godot /// /// Variable that will be hashed. /// Hash of the variable passed. - public static int Hash(object var) + public static int Hash(Variant var) { - using var variant = Marshaling.ConvertManagedObjectToVariant(var); - return NativeFuncs.godotsharp_hash(variant); + return NativeFuncs.godotsharp_hash((godot_variant)var.NativeVar); } /// @@ -515,16 +511,16 @@ namespace Godot /// /// Arguments that will converted to string. /// The string formed by the given arguments. - public static string Str(params object[] what) + public static string Str(params Variant[] what) { - using var whatGodotArray = Marshaling.ConvertSystemArrayToNativeGodotArray(what); - NativeFuncs.godotsharp_str(whatGodotArray, out godot_string ret); + using var whatGodot = new Godot.Collections.Array(what); + NativeFuncs.godotsharp_str((godot_array)whatGodot.NativeValue, out godot_string ret); using (ret) return Marshaling.ConvertStringToManaged(ret); } /// - /// Converts a formatted string that was returned by to the original value. + /// Converts a formatted string that was returned by to the original value. /// /// /// @@ -535,27 +531,25 @@ namespace Godot /// /// String that will be converted to Variant. /// The decoded Variant. - public static object Str2Var(string str) + public static Variant Str2Var(string str) { using var godotStr = Marshaling.ConvertStringToNative(str); NativeFuncs.godotsharp_str2var(godotStr, out godot_variant ret); - using (ret) - return Marshaling.ConvertVariantToManagedObject(ret); + return Variant.CreateTakingOwnershipOfDisposableValue(ret); } /// /// Encodes a Variant value to a byte array. /// If is encoding objects is allowed /// (and can potentially include code). - /// Deserialization can be done with . + /// Deserialization can be done with . /// /// Variant that will be encoded. /// If objects should be serialized. /// The Variant encoded as an array of bytes. - public static byte[] Var2Bytes(object var, bool fullObjects = false) + public static byte[] Var2Bytes(Variant var, bool fullObjects = false) { - using var variant = Marshaling.ConvertManagedObjectToVariant(var); - NativeFuncs.godotsharp_var2bytes(variant, fullObjects.ToGodotBool(), out var varBytes); + NativeFuncs.godotsharp_var2bytes((godot_variant)var.NativeVar, fullObjects.ToGodotBool(), out var varBytes); using (varBytes) return Marshaling.ConvertNativePackedByteArrayToSystemArray(varBytes); } @@ -577,10 +571,9 @@ namespace Godot /// /// Variant that will be converted to string. /// The Variant encoded as a string. - public static string Var2Str(object var) + public static string Var2Str(Variant var) { - using var variant = Marshaling.ConvertManagedObjectToVariant(var); - NativeFuncs.godotsharp_var2str(variant, out godot_string ret); + NativeFuncs.godotsharp_var2str((godot_variant)var.NativeVar, out godot_string ret); using (ret) return Marshaling.ConvertStringToManaged(ret); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs index 8802f229b3e..eee19aea46a 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs @@ -1,7 +1,4 @@ using System; -using System.Collections; -using System.Collections.Generic; -using System.Reflection; using System.Runtime.InteropServices; // ReSharper disable InconsistentNaming @@ -11,8 +8,6 @@ using System.Runtime.InteropServices; #nullable enable -// TODO: Consider removing support for IEnumerable - namespace Godot.NativeInterop { public static class Marshaling @@ -113,10 +108,10 @@ namespace Godot.NativeInterop if (type == typeof(byte[])) return Variant.Type.PackedByteArray; - if (type == typeof(Int32[])) + if (type == typeof(int[])) return Variant.Type.PackedInt32Array; - if (type == typeof(Int64[])) + if (type == typeof(long[])) return Variant.Type.PackedInt64Array; if (type == typeof(float[])) @@ -151,27 +146,6 @@ namespace Godot.NativeInterop } else if (type.IsGenericType) { - var genericTypeDefinition = type.GetGenericTypeDefinition(); - - if (genericTypeDefinition == typeof(Collections.Dictionary<,>)) - return Variant.Type.Dictionary; - - if (genericTypeDefinition == typeof(Collections.Array<>)) - return Variant.Type.Array; - - if (genericTypeDefinition == typeof(System.Collections.Generic.Dictionary<,>)) - return Variant.Type.Dictionary; - - if (genericTypeDefinition == typeof(System.Collections.Generic.List<>)) - return Variant.Type.Array; - - if (genericTypeDefinition == typeof(IDictionary<,>)) - return Variant.Type.Dictionary; - - if (genericTypeDefinition == typeof(ICollection<>) || - genericTypeDefinition == typeof(IEnumerable<>)) - return Variant.Type.Array; - if (typeof(Godot.Object).IsAssignableFrom(type)) return Variant.Type.Object; } @@ -194,15 +168,11 @@ namespace Godot.NativeInterop if (typeof(RID) == type) return Variant.Type.Rid; - if (typeof(Collections.Dictionary) == type || typeof(System.Collections.IDictionary) == type) + if (typeof(Collections.Dictionary) == type) return Variant.Type.Dictionary; - if (typeof(Collections.Array) == type || - typeof(System.Collections.ICollection) == type || - typeof(System.Collections.IEnumerable) == type) - { + if (typeof(Collections.Array) == type) return Variant.Type.Array; - } } break; @@ -214,7 +184,6 @@ namespace Godot.NativeInterop } /* TODO: Reflection and type checking each time is slow. This will be replaced with source generators. */ - public static godot_variant ConvertManagedObjectToVariant(object? p_obj) { if (p_obj == null) @@ -228,19 +197,19 @@ namespace Godot.NativeInterop return VariantUtils.CreateFromInt(@char); case sbyte @int8: return VariantUtils.CreateFromInt(@int8); - case Int16 @int16: + case short @int16: return VariantUtils.CreateFromInt(@int16); - case Int32 @int32: + case int @int32: return VariantUtils.CreateFromInt(@int32); - case Int64 @int64: + case long @int64: return VariantUtils.CreateFromInt(@int64); case byte @uint8: return VariantUtils.CreateFromInt(@uint8); - case UInt16 @uint16: + case ushort @uint16: return VariantUtils.CreateFromInt(@uint16); - case UInt32 @uint32: + case uint @uint32: return VariantUtils.CreateFromInt(@uint32); - case UInt64 @uint64: + case ulong @uint64: return VariantUtils.CreateFromInt(@uint64); case float @float: return VariantUtils.CreateFromFloat(@float); @@ -288,9 +257,9 @@ namespace Godot.NativeInterop return VariantUtils.CreateFromString(@string); case byte[] byteArray: return VariantUtils.CreateFromPackedByteArray(byteArray); - case Int32[] int32Array: + case int[] int32Array: return VariantUtils.CreateFromPackedInt32Array(int32Array); - case Int64[] int64Array: + case long[] int64Array: return VariantUtils.CreateFromPackedInt64Array(int64Array); case float[] floatArray: return VariantUtils.CreateFromPackedFloat32Array(floatArray); @@ -305,11 +274,11 @@ namespace Godot.NativeInterop case Color[] colorArray: return VariantUtils.CreateFromPackedColorArray(colorArray); case StringName[] stringNameArray: - return VariantUtils.CreateFromSystemArrayOfSupportedType(stringNameArray); + return VariantUtils.CreateFromSystemArrayOfStringName(stringNameArray); case NodePath[] nodePathArray: - return VariantUtils.CreateFromSystemArrayOfSupportedType(nodePathArray); + return VariantUtils.CreateFromSystemArrayOfNodePath(nodePathArray); case RID[] ridArray: - return VariantUtils.CreateFromSystemArrayOfSupportedType(ridArray); + return VariantUtils.CreateFromSystemArrayOfRID(ridArray); case Godot.Object[] godotObjectArray: return VariantUtils.CreateFromSystemArrayOfGodotObject(godotObjectArray); case Godot.Object godotObject: @@ -326,49 +295,6 @@ namespace Godot.NativeInterop return VariantUtils.CreateFromArray(godotArray); case Variant variant: return NativeFuncs.godotsharp_variant_new_copy((godot_variant)variant.NativeVar); - case Collections.IGenericGodotDictionary genericGodotDictionary: - { - var godotDict = genericGodotDictionary.UnderlyingDictionary; - if (godotDict == null) - return new godot_variant(); - return VariantUtils.CreateFromDictionary(godotDict); - } - case Collections.IGenericGodotArray genericGodotArray: - { - var godotArray = genericGodotArray.UnderlyingArray; - if (godotArray == null) - return new godot_variant(); - return VariantUtils.CreateFromArray(godotArray); - } - default: - { - var type = p_obj.GetType(); - - if (type.IsGenericType) - { - var genericTypeDefinition = type.GetGenericTypeDefinition(); - - if (genericTypeDefinition == typeof(System.Collections.Generic.Dictionary<,>)) - { - // TODO: Validate key and value types are compatible with Variant - var godotDict = new Collections.Dictionary(); - - foreach (KeyValuePair entry in (IDictionary)p_obj) - godotDict.Add(entry.Key, entry.Value); - - return VariantUtils.CreateFromDictionary(godotDict); - } - - if (genericTypeDefinition == typeof(System.Collections.Generic.List<>)) - { - // TODO: Validate element type is compatible with Variant - using var nativeGodotArray = ConvertICollectionToNativeGodotArray((ICollection)p_obj); - return VariantUtils.CreateFromArray(nativeGodotArray); - } - } - - break; - } } GD.PushError("Attempted to convert an unmarshallable managed type to Variant. Name: '" + @@ -495,11 +421,31 @@ namespace Godot.NativeInterop } if (type.IsArray || type.IsSZArray) + { return ConvertVariantToSystemArrayOfType(p_var, type); + } else if (type.IsGenericType) - return ConvertVariantToManagedObjectOfGenericType(p_var, type); + { + if (typeof(Godot.Object).IsAssignableFrom(type)) + { + 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; + } else if (type == typeof(Variant)) + { return Variant.CreateCopyingBorrowed(p_var); + } if (ConvertVariantToManagedObjectOfClass(p_var, type, out object? res)) return res; @@ -518,10 +464,10 @@ namespace Godot.NativeInterop if (type == typeof(byte[])) return VariantUtils.ConvertAsPackedByteArrayToSystemArray(p_var); - if (type == typeof(Int32[])) + if (type == typeof(int[])) return VariantUtils.ConvertAsPackedInt32ArrayToSystemArray(p_var); - if (type == typeof(Int64[])) + if (type == typeof(long[])) return VariantUtils.ConvertAsPackedInt64ArrayToSystemArray(p_var); if (type == typeof(float[])) @@ -543,13 +489,13 @@ namespace Godot.NativeInterop return VariantUtils.ConvertAsPackedColorArrayToSystemArray(p_var); if (type == typeof(StringName[])) - return VariantUtils.ConvertToSystemArrayOfSupportedType(p_var); + return VariantUtils.ConvertToSystemArrayOfStringName(p_var); if (type == typeof(NodePath[])) - return VariantUtils.ConvertToSystemArrayOfSupportedType(p_var); + return VariantUtils.ConvertToSystemArrayOfNodePath(p_var); if (type == typeof(RID[])) - return VariantUtils.ConvertToSystemArrayOfSupportedType(p_var); + return VariantUtils.ConvertToSystemArrayOfRID(p_var); if (typeof(Godot.Object[]).IsAssignableFrom(type)) return VariantUtils.ConvertToSystemArrayOfGodotObject(p_var, type); @@ -618,15 +564,13 @@ namespace Godot.NativeInterop return true; } - if (typeof(Collections.Dictionary) == type || typeof(System.Collections.IDictionary) == type) + if (typeof(Collections.Dictionary) == type) { res = VariantUtils.ConvertToDictionaryObject(p_var); return true; } - if (typeof(Collections.Array) == type || - typeof(System.Collections.ICollection) == type || - typeof(System.Collections.IEnumerable) == type) + if (typeof(Collections.Array) == type) { res = VariantUtils.ConvertToArrayObject(p_var); return true; @@ -636,103 +580,6 @@ namespace Godot.NativeInterop return false; } - private static object? ConvertVariantToManagedObjectOfGenericType(in godot_variant p_var, Type type) - { - static object ConvertVariantToGenericGodotCollectionsDictionary(in godot_variant p_var, Type fullType) - { - var underlyingDict = VariantUtils.ConvertToDictionaryObject(p_var); - return Activator.CreateInstance(fullType, - BindingFlags.Public | BindingFlags.Instance, null, - args: new object[] { underlyingDict }, null)!; - } - - static object ConvertVariantToGenericGodotCollectionsArray(in godot_variant p_var, Type fullType) - { - var underlyingArray = VariantUtils.ConvertToArrayObject(p_var); - return Activator.CreateInstance(fullType, - BindingFlags.Public | BindingFlags.Instance, null, - args: new object[] { underlyingArray }, null)!; - } - - var genericTypeDefinition = type.GetGenericTypeDefinition(); - - if (genericTypeDefinition == typeof(Collections.Dictionary<,>)) - return ConvertVariantToGenericGodotCollectionsDictionary(p_var, type); - - if (genericTypeDefinition == typeof(Collections.Array<>)) - return ConvertVariantToGenericGodotCollectionsArray(p_var, type); - - if (genericTypeDefinition == typeof(System.Collections.Generic.Dictionary<,>)) - { - using var godotDictionary = VariantUtils.ConvertToDictionaryObject(p_var); - - var dictionary = (System.Collections.IDictionary)Activator.CreateInstance(type, - BindingFlags.Public | BindingFlags.Instance, null, - args: new object[] - { - /* capacity: */ godotDictionary.Count - }, null)!; - - foreach (KeyValuePair pair in godotDictionary) - dictionary.Add(pair.Key, pair.Value); - - return dictionary; - } - - if (genericTypeDefinition == typeof(System.Collections.Generic.List<>)) - { - using var godotArray = VariantUtils.ConvertToArrayObject(p_var); - - var list = (System.Collections.IList)Activator.CreateInstance(type, - BindingFlags.Public | BindingFlags.Instance, null, - args: new object[] - { - /* capacity: */ godotArray.Count - }, null)!; - - foreach (object elem in godotArray) - list.Add(elem); - - return list; - } - - if (genericTypeDefinition == typeof(IDictionary<,>)) - { - var genericArgs = type.GetGenericArguments(); - var keyType = genericArgs[0]; - var valueType = genericArgs[1]; - var genericGodotDictionaryType = typeof(Collections.Dictionary<,>) - .MakeGenericType(keyType, valueType); - - return ConvertVariantToGenericGodotCollectionsDictionary(p_var, genericGodotDictionaryType); - } - - if (genericTypeDefinition == typeof(ICollection<>) || genericTypeDefinition == typeof(IEnumerable<>)) - { - var elementType = type.GetGenericArguments()[0]; - var genericGodotArrayType = typeof(Collections.Array<>) - .MakeGenericType(elementType); - - return ConvertVariantToGenericGodotCollectionsArray(p_var, genericGodotArrayType); - } - - if (typeof(Godot.Object).IsAssignableFrom(type)) - { - 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; - } - public static unsafe object? ConvertVariantToManagedObject(in godot_variant p_var) { switch (p_var.Type) @@ -949,20 +796,6 @@ namespace Godot.NativeInterop // Array - internal static T[] ConvertNativeGodotArrayToSystemArrayOfType(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 - array.CopyToGeneric(ret, 0); - - return ret; - } - internal static T[] ConvertNativeGodotArrayToSystemArrayOfGodotObjectType(in godot_array p_array) where T : Godot.Object { @@ -972,12 +805,13 @@ namespace Godot.NativeInterop int length = array.Count; var ret = new T[length]; - // ConvertVariantToManagedObjectOfType handled by Collections.Array.CopyToGeneric - array.CopyToGeneric(ret, 0); + for (int i = 0; i < length; i++) + ret[i] = (T)array[i].AsGodotObject(); return ret; } + // TODO: This needs reflection. Look for an alternative. internal static Godot.Object[] ConvertNativeGodotArrayToSystemArrayOfGodotObjectType(in godot_array p_array, Type type) { @@ -987,93 +821,52 @@ namespace Godot.NativeInterop int length = array.Count; var ret = (Godot.Object[])Activator.CreateInstance(type, length)!; - // ConvertVariantToManagedObjectOfType handled by Collections.Array.CopyToGeneric - array.CopyToGeneric(ret, 0, type.GetElementType()); + for (int i = 0; i < length; i++) + ret[i] = array[i].AsGodotObject(); return ret; } - public static godot_array ConvertSystemArrayToNativeGodotArray(T[] p_array) + internal static StringName[] ConvertNativeGodotArrayToSystemArrayOfStringName(in godot_array p_array) { - int length = p_array.Length; + var array = Collections.Array.CreateTakingOwnershipOfDisposableValue( + NativeFuncs.godotsharp_array_new_copy(p_array)); - if (length == 0) - return NativeFuncs.godotsharp_array_new(); - - using var array = new Collections.Array(); - array.Resize(length); + int length = array.Count; + var ret = new StringName[length]; for (int i = 0; i < length; i++) - array[i] = p_array[i]; + ret[i] = array[i].AsStringName(); - var src = (godot_array)array.NativeValue; - return NativeFuncs.godotsharp_array_new_copy(src); + return ret; } - public static godot_array ConvertICollectionToNativeGodotArray(ICollection p_array) + internal static NodePath[] ConvertNativeGodotArrayToSystemArrayOfNodePath(in godot_array p_array) { - int length = p_array.Count; + var array = Collections.Array.CreateTakingOwnershipOfDisposableValue( + NativeFuncs.godotsharp_array_new_copy(p_array)); - if (length == 0) - return NativeFuncs.godotsharp_array_new(); + int length = array.Count; + var ret = new NodePath[length]; - using var array = new Collections.Array(); - array.Resize(length); + for (int i = 0; i < length; i++) + ret[i] = array[i].AsNodePath(); - 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); + return ret; } - public static godot_array ConvertGenericICollectionToNativeGodotArray(ICollection p_array) + internal static RID[] ConvertNativeGodotArrayToSystemArrayOfRID(in godot_array p_array) { - int length = p_array.Count; + var array = Collections.Array.CreateTakingOwnershipOfDisposableValue( + NativeFuncs.godotsharp_array_new_copy(p_array)); - if (length == 0) - return NativeFuncs.godotsharp_array_new(); + int length = array.Count; + var ret = new RID[length]; - var array = new Collections.Array(); - using var underlyingArray = (Collections.Array)array; - array.Resize(length); + for (int i = 0; i < length; i++) + ret[i] = array[i].AsRID(); - 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(IEnumerable p_array) - { - var array = new Collections.Array(); - 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); + return ret; } // PackedByteArray diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs index fe0d7104ea4..1ce89659399 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs @@ -210,21 +210,22 @@ namespace Godot.NativeInterop public static godot_variant CreateFromPackedColorArray(Span from) => CreateFromPackedColorArray(Marshaling.ConvertSystemArrayToNativePackedColorArray(from)); - public static godot_variant CreateFromSystemArrayOfSupportedType(T[]? from) - { - if (from == null) - return default; // Nil - using godot_array array = Marshaling.ConvertSystemArrayToNativeGodotArray(from); - return CreateFromArray(array); - } + public static godot_variant CreateFromSystemArrayOfStringName(Span from) + => CreateFromArray(new Collections.Array(from)); + + public static godot_variant CreateFromSystemArrayOfNodePath(Span from) + => CreateFromArray(new Collections.Array(from)); + + public static godot_variant CreateFromSystemArrayOfRID(Span from) + => CreateFromArray(new Collections.Array(from)); // 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); + using var fromGodot = new Collections.Array(from); + return CreateFromArray((godot_array)fromGodot.NativeValue); } public static godot_variant CreateFromArray(godot_array from) @@ -237,45 +238,6 @@ namespace Godot.NativeInterop 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(Collections.Array? 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( - System.Collections.Generic.ICollection? 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( - System.Collections.Generic.IEnumerable? 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); @@ -286,51 +248,6 @@ namespace Godot.NativeInterop public static godot_variant CreateFromDictionary(Dictionary? from) => from != null ? CreateFromDictionary((godot_dictionary)from.NativeValue) : default; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static godot_variant CreateFromDictionary(Dictionary? from) - => from != null ? CreateFromDictionary((godot_dictionary)((Dictionary)from).NativeValue) : default; - - public static godot_variant CreateFromSystemDictionary( - System.Collections.Generic.Dictionary? 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( - System.Collections.Generic.IDictionary? from) - { - 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 CreateFromStringName(godot_string_name from) { NativeFuncs.godotsharp_variant_new_string_name(out godot_variant ret, from); @@ -381,17 +298,17 @@ namespace Godot.NativeInterop p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var)); - public static Int16 ConvertToInt16(in godot_variant p_var) - => (Int16)(p_var.Type == Variant.Type.Int ? + public static short ConvertToInt16(in godot_variant p_var) + => (short)(p_var.Type == Variant.Type.Int ? p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var)); - public static Int32 ConvertToInt32(in godot_variant p_var) - => (Int32)(p_var.Type == Variant.Type.Int ? + public static int ConvertToInt32(in godot_variant p_var) + => (int)(p_var.Type == Variant.Type.Int ? p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var)); - public static Int64 ConvertToInt64(in godot_variant p_var) + public static long ConvertToInt64(in godot_variant p_var) => p_var.Type == Variant.Type.Int ? p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var); public static byte ConvertToUInt8(in godot_variant p_var) @@ -399,18 +316,18 @@ namespace Godot.NativeInterop p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var)); - public static UInt16 ConvertToUInt16(in godot_variant p_var) - => (UInt16)(p_var.Type == Variant.Type.Int ? + public static ushort ConvertToUInt16(in godot_variant p_var) + => (ushort)(p_var.Type == Variant.Type.Int ? p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var)); - public static UInt32 ConvertToUInt32(in godot_variant p_var) - => (UInt32)(p_var.Type == Variant.Type.Int ? + public static uint ConvertToUInt32(in godot_variant p_var) + => (uint)(p_var.Type == Variant.Type.Int ? p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var)); - public static UInt64 ConvertToUInt64(in godot_variant p_var) - => (UInt64)(p_var.Type == Variant.Type.Int ? + public static ulong ConvertToUInt64(in godot_variant p_var) + => (ulong)(p_var.Type == Variant.Type.Int ? p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var)); @@ -642,10 +559,22 @@ namespace Godot.NativeInterop return Marshaling.ConvertNativePackedColorArrayToSystemArray(packedArray); } - public static T[] ConvertToSystemArrayOfSupportedType(in godot_variant p_var) + public static StringName[] ConvertToSystemArrayOfStringName(in godot_variant p_var) { using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); - return Marshaling.ConvertNativeGodotArrayToSystemArrayOfType(godotArray); + return Marshaling.ConvertNativeGodotArrayToSystemArrayOfStringName(godotArray); + } + + public static NodePath[] ConvertToSystemArrayOfNodePath(in godot_variant p_var) + { + using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); + return Marshaling.ConvertNativeGodotArrayToSystemArrayOfNodePath(godotArray); + } + + public static RID[] ConvertToSystemArrayOfRID(in godot_variant p_var) + { + using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); + return Marshaling.ConvertNativeGodotArrayToSystemArrayOfRID(godotArray); } public static T[] ConvertToSystemArrayOfGodotObject(in godot_variant p_var) @@ -662,37 +591,5 @@ namespace Godot.NativeInterop using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); return Marshaling.ConvertNativeGodotArrayToSystemArrayOfGodotObjectType(godotArray, type); } - - public static Array ConvertToGenericArrayObject(in godot_variant p_var) => - new(ConvertToArrayObject(p_var)); - - public static Dictionary ConvertToGenericDictionaryObject(in godot_variant p_var) => - new(ConvertToDictionaryObject(p_var)); - - public static System.Collections.Generic.List ConvertToSystemGenericList(in godot_variant p_var) - { - var godotArray = ConvertToArrayObject(p_var); - - var res = new System.Collections.Generic.List(godotArray.Count); - - foreach (object elem in godotArray) - res.Add((T)elem); - - return res; - } - - public static System.Collections.Generic.Dictionary - ConvertToSystemGenericDictionary(in godot_variant p_var) - where TKey : notnull - { - var godotDictionary = ConvertToDictionaryObject(p_var); - - var res = new System.Collections.Generic.Dictionary(godotDictionary.Count); - - foreach (System.Collections.Generic.KeyValuePair pair in godotDictionary) - res.Add((TKey)pair.Key, (TValue)pair.Value); - - return res; - } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs index 04920ccfab3..5cb678c280d 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs @@ -187,18 +187,6 @@ namespace Godot return null; } - internal static bool InternalIsClassNativeBase(Type t) - { - // Check whether the type is declared in the GodotSharp or GodotSharpEditor assemblies - var typeAssembly = t.Assembly; - - if (typeAssembly == CachedType.Assembly) - return true; - - var typeAssemblyName = t.Assembly.GetName(); - return typeAssemblyName.Name == "GodotSharpEditor"; - } - // ReSharper disable once VirtualMemberNeverOverridden.Global protected internal virtual bool SetGodotClassPropertyValue(in godot_string_name name, in godot_variant value) { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs index 8ba3c403fa5..96fb8910866 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs @@ -4,10 +4,10 @@ using Godot.NativeInterop; namespace Godot { - public class SignalAwaiter : IAwaiter, IAwaitable + public class SignalAwaiter : IAwaiter, IAwaitable { private bool _completed; - private object[] _result; + private Variant[] _result; private Action _continuation; public SignalAwaiter(Object source, StringName signal, Object target) @@ -26,9 +26,9 @@ namespace Godot _continuation = continuation; } - public object[] GetResult() => _result; + public Variant[] GetResult() => _result; - public IAwaiter GetAwaiter() => this; + public IAwaiter GetAwaiter() => this; [UnmanagedCallersOnly] internal static unsafe void SignalCallback(IntPtr awaiterGCHandlePtr, godot_variant** args, int argCount, @@ -48,10 +48,10 @@ namespace Godot awaiter._completed = true; - object[] signalArgs = new object[argCount]; + Variant[] signalArgs = new Variant[argCount]; for (int i = 0; i < argCount; i++) - signalArgs[i] = Marshaling.ConvertVariantToManagedObject(*args[i]); + signalArgs[i] = Variant.CreateCopyingBorrowed(*args[i]); awaiter._result = signalArgs; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj index 0a61069a1e2..d1ff6ade8af 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj +++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj @@ -78,7 +78,6 @@ - diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs b/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs index c1c321829a5..7c4df291ac1 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs @@ -105,6 +105,8 @@ public partial struct Variant : IDisposable // TODO: Consider renaming Variant.Type to VariantType and this property to Type. VariantType would also avoid ambiguity with System.Type. public Type VariantType => NativeVar.DangerousSelfRef.Type; + public override string ToString() => AsString(); + public object? Obj { get @@ -116,8 +118,6 @@ public partial struct Variant : IDisposable } } - // TODO: Consider implicit operators - [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool AsBool() => VariantUtils.ConvertToBool((godot_variant)NativeVar); @@ -210,6 +210,18 @@ public partial struct Variant : IDisposable public Transform3D AsTransform3D() => VariantUtils.ConvertToTransform3D((godot_variant)NativeVar); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 AsVector4() => + VariantUtils.ConvertToVector4((godot_variant)NativeVar); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4i AsVector4i() => + VariantUtils.ConvertToVector4i((godot_variant)NativeVar); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Projection AsProjection() => + VariantUtils.ConvertToProjection((godot_variant)NativeVar); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public AABB AsAABB() => VariantUtils.ConvertToAABB((godot_variant)NativeVar); @@ -272,25 +284,16 @@ public partial struct Variant : IDisposable VariantUtils.ConvertToSystemArrayOfGodotObject((godot_variant)NativeVar); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public T[] AsSystemArrayOfSupportedType() => - VariantUtils.ConvertToSystemArrayOfSupportedType((godot_variant)NativeVar); + public StringName[] AsSystemArrayOfStringName() => + VariantUtils.ConvertToSystemArrayOfStringName((godot_variant)NativeVar); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Collections.Dictionary AsGodotGenericDictionary() => - VariantUtils.ConvertToGenericDictionaryObject((godot_variant)NativeVar); + public NodePath[] AsSystemArrayOfNodePath() => + VariantUtils.ConvertToSystemArrayOfNodePath((godot_variant)NativeVar); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Collections.Array AsGodotGenericArray() => - VariantUtils.ConvertToGenericArrayObject((godot_variant)NativeVar); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public System.Collections.Generic.Dictionary AsSystemGenericDictionary() - where TKey : notnull => - VariantUtils.ConvertToSystemGenericDictionary((godot_variant)NativeVar); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public System.Collections.Generic.List AsSystemGenericList() => - VariantUtils.ConvertToSystemGenericList((godot_variant)NativeVar); + public RID[] AsSystemArrayOfRID() => + VariantUtils.ConvertToSystemArrayOfRID((godot_variant)NativeVar); [MethodImpl(MethodImplOptions.AggressiveInlining)] public Godot.Object AsGodotObject() => @@ -387,6 +390,15 @@ public partial struct Variant : IDisposable [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Transform3D(Variant from) => from.AsTransform3D(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static explicit operator Vector4(Variant from) => from.AsVector4(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static explicit operator Vector4i(Variant from) => from.AsVector4i(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static explicit operator Projection(Variant from) => from.AsProjection(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator AABB(Variant from) => from.AsAABB(); @@ -429,6 +441,15 @@ public partial struct Variant : IDisposable [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Color[](Variant from) => from.AsColorArray(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static explicit operator StringName[](Variant from) => from.AsSystemArrayOfStringName(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static explicit operator NodePath[](Variant from) => from.AsSystemArrayOfNodePath(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static explicit operator RID[](Variant from) => from.AsSystemArrayOfRID(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Godot.Object(Variant from) => from.AsGodotObject(); @@ -447,6 +468,161 @@ public partial struct Variant : IDisposable [MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Collections.Array(Variant from) => from.AsGodotArray(); + // While we provide implicit conversion operators, normal methods are still needed for + // casts that are not done implicitly (e.g.: raw array to Span, enum to integer, etc). + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(bool from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(char from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(sbyte from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(short from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(int from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(long from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(byte from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(ushort from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(uint from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(ulong from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(float from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(double from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(string from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Vector2 from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Vector2i from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Rect2 from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Rect2i from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Transform2D from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Vector3 from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Vector3i from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Basis from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Quaternion from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Transform3D from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Vector4 from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Vector4i from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Projection from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(AABB from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Color from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Plane from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Callable from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(SignalInfo from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Span from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Span from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Span from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Span from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Span from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Span from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Span from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Span from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Span from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Godot.Object[] from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Span from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Span from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Span from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Godot.Object from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(StringName from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(NodePath from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(RID from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Collections.Dictionary from) => from; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Variant CreateFrom(Collections.Array from) => from; + + // Implicit conversion operators + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Variant(bool from) => CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromBool(from)); @@ -539,6 +715,18 @@ public partial struct Variant : IDisposable public static implicit operator Variant(Transform3D from) => CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromTransform3D(from)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Variant(Vector4 from) => + CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromVector4(from)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Variant(Vector4i from) => + CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromVector4i(from)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Variant(Projection from) => + CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromProjection(from)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Variant(AABB from) => CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromAABB(from)); @@ -596,36 +784,20 @@ public partial struct Variant : IDisposable CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromPackedColorArray(from)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Variant(Godot.Object[]? from) => + public static implicit operator Variant(Godot.Object[] from) => CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSystemArrayOfGodotObject(from)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Variant From(Collections.Dictionary from) => - CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromDictionary(from)); + public static implicit operator Variant(Span from) => + CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSystemArrayOfStringName(from)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Variant From(Collections.Array from) => - CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromArray(from)); + public static implicit operator Variant(Span from) => + CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSystemArrayOfNodePath(from)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Variant From(System.Collections.Generic.Dictionary from) - where TKey : notnull => CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSystemDictionary(from)); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Variant From(System.Collections.Generic.List from) => - CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSystemICollection(from)); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Variant From(System.Collections.Generic.IDictionary from) => - CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSystemGenericIDictionary(from)); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Variant From(System.Collections.Generic.ICollection from) => - CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSystemGenericICollection(from)); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Variant From(System.Collections.Generic.IEnumerable from) => - CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSystemGenericIEnumerable(from)); + public static implicit operator Variant(Span from) => + CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSystemArrayOfRID(from)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Variant(Godot.Object from) => @@ -650,16 +822,4 @@ public partial struct Variant : IDisposable [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Variant(Collections.Array from) => CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromArray(from)); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Variant From(System.Collections.IDictionary from) => - CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSystemIDictionary(from)); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Variant From(System.Collections.ICollection from) => - CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSystemICollection(from)); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Variant From(System.Collections.IEnumerable from) => - CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSystemIEnumerable(from)); }