From 3123be2384c14f7dd156b1cc2d53d822002b837a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ignacio=20Rold=C3=A1n=20Etcheverry?= Date: Thu, 28 Jul 2022 17:41:50 +0200 Subject: [PATCH] C#: Array, Dictionary and marshaling refactoring - Array and Dictionary now store `Variant` instead of `System.Object`. - Removed generic Array and Dictionary. They cause too much issues, heavily relying on reflection and very limited by the lack of a generic specialization. - Removed support for non-Godot collections. Support for them also relied heavily on reflection for marshaling. Support for them will likely be re-introduced in the future, but it will have to rely on source generators instead of reflection. - Reduced our use of reflection. The remaining usages will be moved to source generators soon. The only usage that I'm not sure yet how to replace is dynamic invocation of delegates. --- .../ExportedFields.cs | 35 +- .../ExportedProperties.cs | 35 +- .../Godot.SourceGenerators/MarshalType.cs | 16 +- .../Godot.SourceGenerators/MarshalUtils.cs | 277 +++++---- .../ScriptMethodsGenerator.cs | 4 +- .../ScriptPropertiesGenerator.cs | 4 +- .../ScriptSerializationGenerator.cs | 28 +- .../ScriptSignalsGenerator.cs | 2 +- .../GodotTools/GodotTools/Build/BuildInfo.cs | 2 +- .../GodotTools/Build/BuildOutputView.cs | 9 +- .../GodotTools/Build/BuildSystem.cs | 9 +- .../GodotTools/GodotTools/GodotSharpEditor.cs | 4 +- .../GodotTools/Ides/Rider/RiderPathManager.cs | 4 +- modules/mono/editor/bindings_generator.cpp | 18 +- .../glue/GodotSharp/GodotSharp/Core/Array.cs | 454 ++++---------- .../Core/Bridge/CSharpInstanceBridge.cs | 14 +- .../Core/Bridge/GodotSerializationInfo.cs | 40 +- .../GodotSharp/Core/Bridge/MethodInfo.cs | 6 +- .../Core/Bridge/ScriptManagerBridge.cs | 12 +- .../GodotSharp/GodotSharp/Core/Callable.cs | 12 +- .../GodotSharp/Core/DelegateUtils.cs | 30 +- .../GodotSharp/GodotSharp/Core/Dictionary.cs | 554 ++---------------- .../Core/Extensions/SceneTreeExtensions.cs | 66 --- .../glue/GodotSharp/GodotSharp/Core/GD.cs | 43 +- .../Core/NativeInterop/Marshaling.cs | 349 +++-------- .../Core/NativeInterop/VariantUtils.cs | 173 ++---- .../GodotSharp/GodotSharp/Core/Object.base.cs | 12 - .../GodotSharp/Core/SignalAwaiter.cs | 12 +- .../GodotSharp/GodotSharp/GodotSharp.csproj | 1 - .../glue/GodotSharp/GodotSharp/Variant.cs | 264 +++++++-- 30 files changed, 766 insertions(+), 1723 deletions(-) delete mode 100644 modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs 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)); }