Merge pull request #69428 from neikeq/no

C#: Cleanup of Marshaling methods
This commit is contained in:
Rémi Verschelde 2022-12-02 16:48:17 +01:00
commit d746b618be
No known key found for this signature in database
GPG key ID: C3336907360768E1
18 changed files with 479 additions and 971 deletions

View file

@ -268,8 +268,9 @@ namespace Godot.SourceGenerators
if (parameters.Length > paramTypes.Length)
return null; // Ignore incompatible method
return new GodotMethodData(method, paramTypes, parameters
.Select(p => p.Type).ToImmutableArray(), retType, retSymbol);
return new GodotMethodData(method, paramTypes,
parameters.Select(p => p.Type).ToImmutableArray(),
retType != null ? (retType.Value, retSymbol) : null);
}
public static IEnumerable<GodotMethodData> WhereHasGodotCompatibleSignature(
@ -330,10 +331,10 @@ namespace Godot.SourceGenerators
public static string Path(this Location location)
=> location.SourceTree?.GetLineSpan(location.SourceSpan).Path
?? location.GetLineSpan().Path;
?? location.GetLineSpan().Path;
public static int StartLine(this Location location)
=> location.SourceTree?.GetLineSpan(location.SourceSpan).StartLinePosition.Line
?? location.GetLineSpan().StartLinePosition.Line;
?? location.GetLineSpan().StartLinePosition.Line;
}
}

View file

@ -6,20 +6,18 @@ namespace Godot.SourceGenerators
public readonly struct GodotMethodData
{
public GodotMethodData(IMethodSymbol method, ImmutableArray<MarshalType> paramTypes,
ImmutableArray<ITypeSymbol> paramTypeSymbols, MarshalType? retType, ITypeSymbol? retSymbol)
ImmutableArray<ITypeSymbol> paramTypeSymbols, (MarshalType MarshalType, ITypeSymbol TypeSymbol)? retType)
{
Method = method;
ParamTypes = paramTypes;
ParamTypeSymbols = paramTypeSymbols;
RetType = retType;
RetSymbol = retSymbol;
}
public IMethodSymbol Method { get; }
public ImmutableArray<MarshalType> ParamTypes { get; }
public ImmutableArray<ITypeSymbol> ParamTypeSymbols { get; }
public MarshalType? RetType { get; }
public ITypeSymbol? RetSymbol { get; }
public (MarshalType MarshalType, ITypeSymbol TypeSymbol)? RetType { get; }
}
public readonly struct GodotSignalDelegateData

View file

@ -304,240 +304,33 @@ namespace Godot.SourceGenerators
{
return marshalType switch
{
MarshalType.Boolean =>
source.Append(VariantUtils, ".ConvertToBool(", inputExpr, ")"),
MarshalType.Char =>
source.Append("(char)", VariantUtils, ".ConvertToUInt16(", inputExpr, ")"),
MarshalType.SByte =>
source.Append(VariantUtils, ".ConvertToInt8(", inputExpr, ")"),
MarshalType.Int16 =>
source.Append(VariantUtils, ".ConvertToInt16(", inputExpr, ")"),
MarshalType.Int32 =>
source.Append(VariantUtils, ".ConvertToInt32(", inputExpr, ")"),
MarshalType.Int64 =>
source.Append(VariantUtils, ".ConvertToInt64(", inputExpr, ")"),
MarshalType.Byte =>
source.Append(VariantUtils, ".ConvertToUInt8(", inputExpr, ")"),
MarshalType.UInt16 =>
source.Append(VariantUtils, ".ConvertToUInt16(", inputExpr, ")"),
MarshalType.UInt32 =>
source.Append(VariantUtils, ".ConvertToUInt32(", inputExpr, ")"),
MarshalType.UInt64 =>
source.Append(VariantUtils, ".ConvertToUInt64(", inputExpr, ")"),
MarshalType.Single =>
source.Append(VariantUtils, ".ConvertToFloat32(", inputExpr, ")"),
MarshalType.Double =>
source.Append(VariantUtils, ".ConvertToFloat64(", inputExpr, ")"),
MarshalType.String =>
source.Append(VariantUtils, ".ConvertToStringObject(", inputExpr, ")"),
MarshalType.Vector2 =>
source.Append(VariantUtils, ".ConvertToVector2(", inputExpr, ")"),
MarshalType.Vector2i =>
source.Append(VariantUtils, ".ConvertToVector2i(", inputExpr, ")"),
MarshalType.Rect2 =>
source.Append(VariantUtils, ".ConvertToRect2(", inputExpr, ")"),
MarshalType.Rect2i =>
source.Append(VariantUtils, ".ConvertToRect2i(", inputExpr, ")"),
MarshalType.Transform2D =>
source.Append(VariantUtils, ".ConvertToTransform2D(", inputExpr, ")"),
MarshalType.Vector3 =>
source.Append(VariantUtils, ".ConvertToVector3(", inputExpr, ")"),
MarshalType.Vector3i =>
source.Append(VariantUtils, ".ConvertToVector3i(", inputExpr, ")"),
MarshalType.Basis =>
source.Append(VariantUtils, ".ConvertToBasis(", inputExpr, ")"),
MarshalType.Quaternion =>
source.Append(VariantUtils, ".ConvertToQuaternion(", inputExpr, ")"),
MarshalType.Transform3D =>
source.Append(VariantUtils, ".ConvertToTransform3D(", inputExpr, ")"),
MarshalType.Vector4 =>
source.Append(VariantUtils, ".ConvertToVector4(", inputExpr, ")"),
MarshalType.Vector4i =>
source.Append(VariantUtils, ".ConvertToVector4i(", inputExpr, ")"),
MarshalType.Projection =>
source.Append(VariantUtils, ".ConvertToProjection(", inputExpr, ")"),
MarshalType.AABB =>
source.Append(VariantUtils, ".ConvertToAABB(", inputExpr, ")"),
MarshalType.Color =>
source.Append(VariantUtils, ".ConvertToColor(", inputExpr, ")"),
MarshalType.Plane =>
source.Append(VariantUtils, ".ConvertToPlane(", inputExpr, ")"),
MarshalType.Callable =>
source.Append(VariantUtils, ".ConvertToCallableManaged(", inputExpr, ")"),
MarshalType.SignalInfo =>
source.Append(VariantUtils, ".ConvertToSignalInfo(", inputExpr, ")"),
MarshalType.Enum =>
source.Append("(", typeSymbol.FullQualifiedNameIncludeGlobal(),
")", VariantUtils, ".ConvertToInt32(", inputExpr, ")"),
MarshalType.ByteArray =>
source.Append(VariantUtils, ".ConvertAsPackedByteArrayToSystemArray(", inputExpr, ")"),
MarshalType.Int32Array =>
source.Append(VariantUtils, ".ConvertAsPackedInt32ArrayToSystemArray(", inputExpr, ")"),
MarshalType.Int64Array =>
source.Append(VariantUtils, ".ConvertAsPackedInt64ArrayToSystemArray(", inputExpr, ")"),
MarshalType.Float32Array =>
source.Append(VariantUtils, ".ConvertAsPackedFloat32ArrayToSystemArray(", inputExpr, ")"),
MarshalType.Float64Array =>
source.Append(VariantUtils, ".ConvertAsPackedFloat64ArrayToSystemArray(", inputExpr, ")"),
MarshalType.StringArray =>
source.Append(VariantUtils, ".ConvertAsPackedStringArrayToSystemArray(", inputExpr, ")"),
MarshalType.Vector2Array =>
source.Append(VariantUtils, ".ConvertAsPackedVector2ArrayToSystemArray(", inputExpr, ")"),
MarshalType.Vector3Array =>
source.Append(VariantUtils, ".ConvertAsPackedVector3ArrayToSystemArray(", inputExpr, ")"),
MarshalType.ColorArray =>
source.Append(VariantUtils, ".ConvertAsPackedColorArrayToSystemArray(", inputExpr, ")"),
MarshalType.GodotObjectOrDerivedArray =>
source.Append(VariantUtils, ".ConvertToSystemArrayOfGodotObject<",
((IArrayTypeSymbol)typeSymbol).ElementType.FullQualifiedNameIncludeGlobal(), ">(", 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 =>
source.Append("(", typeSymbol.FullQualifiedNameIncludeGlobal(),
")", VariantUtils, ".ConvertToGodotObject(", inputExpr, ")"),
MarshalType.StringName =>
source.Append(VariantUtils, ".ConvertToStringNameObject(", inputExpr, ")"),
MarshalType.NodePath =>
source.Append(VariantUtils, ".ConvertToNodePathObject(", inputExpr, ")"),
MarshalType.RID =>
source.Append(VariantUtils, ".ConvertToRID(", inputExpr, ")"),
MarshalType.GodotDictionary =>
source.Append(VariantUtils, ".ConvertToDictionaryObject(", inputExpr, ")"),
MarshalType.GodotArray =>
source.Append(VariantUtils, ".ConvertToArrayObject(", inputExpr, ")"),
// For generic Godot collections, VariantUtils.ConvertTo<T> is slower, so we need this special case
MarshalType.GodotGenericDictionary =>
source.Append(VariantUtils, ".ConvertToDictionaryObject<",
((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedNameIncludeGlobal(), ", ",
((INamedTypeSymbol)typeSymbol).TypeArguments[1].FullQualifiedNameIncludeGlobal(), ">(", inputExpr, ")"),
((INamedTypeSymbol)typeSymbol).TypeArguments[1].FullQualifiedNameIncludeGlobal(), ">(",
inputExpr, ")"),
MarshalType.GodotGenericArray =>
source.Append(VariantUtils, ".ConvertToArrayObject<",
((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedNameIncludeGlobal(), ">(", inputExpr, ")"),
_ => throw new ArgumentOutOfRangeException(nameof(marshalType), marshalType,
"Received unexpected marshal type")
((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedNameIncludeGlobal(), ">(",
inputExpr, ")"),
_ => source.Append(VariantUtils, ".ConvertTo<",
typeSymbol.FullQualifiedNameIncludeGlobal(), ">(", inputExpr, ")"),
};
}
public static StringBuilder AppendManagedToNativeVariantExpr(
this StringBuilder source, string inputExpr, MarshalType marshalType)
public static StringBuilder AppendManagedToNativeVariantExpr(this StringBuilder source,
string inputExpr, ITypeSymbol typeSymbol, MarshalType marshalType)
{
return marshalType switch
{
MarshalType.Boolean =>
source.Append(VariantUtils, ".CreateFromBool(", inputExpr, ")"),
MarshalType.Char =>
source.Append(VariantUtils, ".CreateFromInt((ushort)", inputExpr, ")"),
MarshalType.SByte =>
source.Append(VariantUtils, ".CreateFromInt(", inputExpr, ")"),
MarshalType.Int16 =>
source.Append(VariantUtils, ".CreateFromInt(", inputExpr, ")"),
MarshalType.Int32 =>
source.Append(VariantUtils, ".CreateFromInt(", inputExpr, ")"),
MarshalType.Int64 =>
source.Append(VariantUtils, ".CreateFromInt(", inputExpr, ")"),
MarshalType.Byte =>
source.Append(VariantUtils, ".CreateFromInt(", inputExpr, ")"),
MarshalType.UInt16 =>
source.Append(VariantUtils, ".CreateFromInt(", inputExpr, ")"),
MarshalType.UInt32 =>
source.Append(VariantUtils, ".CreateFromInt(", inputExpr, ")"),
MarshalType.UInt64 =>
source.Append(VariantUtils, ".CreateFromInt(", inputExpr, ")"),
MarshalType.Single =>
source.Append(VariantUtils, ".CreateFromFloat(", inputExpr, ")"),
MarshalType.Double =>
source.Append(VariantUtils, ".CreateFromFloat(", inputExpr, ")"),
MarshalType.String =>
source.Append(VariantUtils, ".CreateFromString(", inputExpr, ")"),
MarshalType.Vector2 =>
source.Append(VariantUtils, ".CreateFromVector2(", inputExpr, ")"),
MarshalType.Vector2i =>
source.Append(VariantUtils, ".CreateFromVector2i(", inputExpr, ")"),
MarshalType.Rect2 =>
source.Append(VariantUtils, ".CreateFromRect2(", inputExpr, ")"),
MarshalType.Rect2i =>
source.Append(VariantUtils, ".CreateFromRect2i(", inputExpr, ")"),
MarshalType.Transform2D =>
source.Append(VariantUtils, ".CreateFromTransform2D(", inputExpr, ")"),
MarshalType.Vector3 =>
source.Append(VariantUtils, ".CreateFromVector3(", inputExpr, ")"),
MarshalType.Vector3i =>
source.Append(VariantUtils, ".CreateFromVector3i(", inputExpr, ")"),
MarshalType.Basis =>
source.Append(VariantUtils, ".CreateFromBasis(", inputExpr, ")"),
MarshalType.Quaternion =>
source.Append(VariantUtils, ".CreateFromQuaternion(", inputExpr, ")"),
MarshalType.Transform3D =>
source.Append(VariantUtils, ".CreateFromTransform3D(", inputExpr, ")"),
MarshalType.Vector4 =>
source.Append(VariantUtils, ".CreateFromVector4(", inputExpr, ")"),
MarshalType.Vector4i =>
source.Append(VariantUtils, ".CreateFromVector4i(", inputExpr, ")"),
MarshalType.Projection =>
source.Append(VariantUtils, ".CreateFromProjection(", inputExpr, ")"),
MarshalType.AABB =>
source.Append(VariantUtils, ".CreateFromAABB(", inputExpr, ")"),
MarshalType.Color =>
source.Append(VariantUtils, ".CreateFromColor(", inputExpr, ")"),
MarshalType.Plane =>
source.Append(VariantUtils, ".CreateFromPlane(", inputExpr, ")"),
MarshalType.Callable =>
source.Append(VariantUtils, ".CreateFromCallable(", inputExpr, ")"),
MarshalType.SignalInfo =>
source.Append(VariantUtils, ".CreateFromSignalInfo(", inputExpr, ")"),
MarshalType.Enum =>
source.Append(VariantUtils, ".CreateFromInt((int)", inputExpr, ")"),
MarshalType.ByteArray =>
source.Append(VariantUtils, ".CreateFromPackedByteArray(", inputExpr, ")"),
MarshalType.Int32Array =>
source.Append(VariantUtils, ".CreateFromPackedInt32Array(", inputExpr, ")"),
MarshalType.Int64Array =>
source.Append(VariantUtils, ".CreateFromPackedInt64Array(", inputExpr, ")"),
MarshalType.Float32Array =>
source.Append(VariantUtils, ".CreateFromPackedFloat32Array(", inputExpr, ")"),
MarshalType.Float64Array =>
source.Append(VariantUtils, ".CreateFromPackedFloat64Array(", inputExpr, ")"),
MarshalType.StringArray =>
source.Append(VariantUtils, ".CreateFromPackedStringArray(", inputExpr, ")"),
MarshalType.Vector2Array =>
source.Append(VariantUtils, ".CreateFromPackedVector2Array(", inputExpr, ")"),
MarshalType.Vector3Array =>
source.Append(VariantUtils, ".CreateFromPackedVector3Array(", inputExpr, ")"),
MarshalType.ColorArray =>
source.Append(VariantUtils, ".CreateFromPackedColorArray(", inputExpr, ")"),
MarshalType.GodotObjectOrDerivedArray =>
source.Append(VariantUtils, ".CreateFromSystemArrayOfGodotObject(", inputExpr, ")"),
MarshalType.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 =>
source.Append(VariantUtils, ".CreateFromGodotObject(", inputExpr, ")"),
MarshalType.StringName =>
source.Append(VariantUtils, ".CreateFromStringName(", inputExpr, ")"),
MarshalType.NodePath =>
source.Append(VariantUtils, ".CreateFromNodePath(", inputExpr, ")"),
MarshalType.RID =>
source.Append(VariantUtils, ".CreateFromRID(", inputExpr, ")"),
MarshalType.GodotDictionary =>
source.Append(VariantUtils, ".CreateFromDictionary(", inputExpr, ")"),
MarshalType.GodotArray =>
source.Append(VariantUtils, ".CreateFromArray(", inputExpr, ")"),
// For generic Godot collections, VariantUtils.CreateFrom<T> is slower, so we need this special case
MarshalType.GodotGenericDictionary =>
source.Append(VariantUtils, ".CreateFromDictionary(", inputExpr, ")"),
MarshalType.GodotGenericArray =>
source.Append(VariantUtils, ".CreateFromArray(", inputExpr, ")"),
_ => throw new ArgumentOutOfRangeException(nameof(marshalType), marshalType,
"Received unexpected marshal type")
_ => source.Append(VariantUtils, ".CreateFrom<",
typeSymbol.FullQualifiedNameIncludeGlobal(), ">(", inputExpr, ")"),
};
}
@ -546,137 +339,30 @@ namespace Godot.SourceGenerators
{
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.FullQualifiedNameIncludeGlobal(), ")", 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.FullQualifiedNameIncludeGlobal(), ">()"),
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.FullQualifiedNameIncludeGlobal(), ")", 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()"),
MarshalType.GodotGenericDictionary => source.Append(inputExpr, ".AsGodotDictionary<",
((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedNameIncludeGlobal(), ", ",
((INamedTypeSymbol)typeSymbol).TypeArguments[1].FullQualifiedNameIncludeGlobal(), ">()"),
MarshalType.GodotGenericArray => source.Append(inputExpr, ".AsGodotArray<",
((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedNameIncludeGlobal(), ">()"),
_ => throw new ArgumentOutOfRangeException(nameof(marshalType), marshalType,
"Received unexpected marshal type")
// For generic Godot collections, Variant.As<T> is slower, so we need this special case
MarshalType.GodotGenericDictionary =>
source.Append(inputExpr, ".AsGodotDictionary<",
((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedNameIncludeGlobal(), ", ",
((INamedTypeSymbol)typeSymbol).TypeArguments[1].FullQualifiedNameIncludeGlobal(), ">()"),
MarshalType.GodotGenericArray =>
source.Append(inputExpr, ".AsGodotArray<",
((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedNameIncludeGlobal(), ">()"),
_ => source.Append(inputExpr, ".As<",
typeSymbol.FullQualifiedNameIncludeGlobal(), ">()")
};
}
public static StringBuilder AppendManagedToVariantExpr(this StringBuilder source,
string inputExpr, MarshalType marshalType)
string inputExpr, ITypeSymbol typeSymbol, MarshalType marshalType)
{
switch (marshalType)
return marshalType switch
{
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:
case MarshalType.GodotGenericDictionary:
case MarshalType.GodotGenericArray:
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");
}
// For generic Godot collections, Variant.From<T> is slower, so we need this special case
MarshalType.GodotGenericDictionary or MarshalType.GodotGenericArray =>
source.Append("global::Godot.Variant.CreateFrom(", inputExpr, ")"),
_ => source.Append("global::Godot.Variant.From<",
typeSymbol.FullQualifiedNameIncludeGlobal(), ">(", inputExpr, ")")
};
}
}
}

View file

@ -135,7 +135,8 @@ namespace Godot.SourceGenerators
source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
source.Append($" public new class MethodName : {symbol.BaseType.FullQualifiedNameIncludeGlobal()}.MethodName {{\n");
source.Append(
$" public new class MethodName : {symbol.BaseType.FullQualifiedNameIncludeGlobal()}.MethodName {{\n");
// Generate cached StringNames for methods and properties, for fast lookup
@ -297,7 +298,7 @@ namespace Godot.SourceGenerators
if (method.RetType != null)
{
returnVal = DeterminePropertyInfo(method.RetType.Value, name: string.Empty);
returnVal = DeterminePropertyInfo(method.RetType.Value.MarshalType, name: string.Empty);
}
else
{
@ -391,7 +392,8 @@ namespace Godot.SourceGenerators
{
source.Append(" ret = ");
source.AppendManagedToNativeVariantExpr("callRet", method.RetType.Value);
source.AppendManagedToNativeVariantExpr("callRet",
method.RetType.Value.TypeSymbol, method.RetType.Value.MarshalType);
source.Append(";\n");
source.Append(" return true;\n");

View file

@ -124,7 +124,8 @@ namespace Godot.SourceGenerators
source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
source.Append($" public new class PropertyName : {symbol.BaseType.FullQualifiedNameIncludeGlobal()}.PropertyName {{\n");
source.Append(
$" public new class PropertyName : {symbol.BaseType.FullQualifiedNameIncludeGlobal()}.PropertyName {{\n");
// Generate cached StringNames for methods and properties, for fast lookup
@ -199,14 +200,14 @@ namespace Godot.SourceGenerators
foreach (var property in godotClassProperties)
{
GeneratePropertyGetter(property.PropertySymbol.Name,
property.Type, source, isFirstEntry);
property.PropertySymbol.Type, property.Type, source, isFirstEntry);
isFirstEntry = false;
}
foreach (var field in godotClassFields)
{
GeneratePropertyGetter(field.FieldSymbol.Name,
field.Type, source, isFirstEntry);
field.FieldSymbol.Type, field.Type, source, isFirstEntry);
isFirstEntry = false;
}
@ -303,6 +304,7 @@ namespace Godot.SourceGenerators
private static void GeneratePropertyGetter(
string propertyMemberName,
ITypeSymbol propertyTypeSymbol,
MarshalType propertyMarshalType,
StringBuilder source,
bool isFirstEntry
@ -317,7 +319,8 @@ namespace Godot.SourceGenerators
.Append(propertyMemberName)
.Append(") {\n")
.Append(" value = ")
.AppendManagedToNativeVariantExpr("this." + propertyMemberName, propertyMarshalType)
.AppendManagedToNativeVariantExpr("this." + propertyMemberName,
propertyTypeSymbol, propertyMarshalType)
.Append(";\n")
.Append(" return true;\n")
.Append(" }\n");
@ -376,7 +379,8 @@ namespace Godot.SourceGenerators
if (propertyUsage != PropertyUsageFlags.Category && attr.ConstructorArguments.Length > 1)
hintString = attr.ConstructorArguments[1].Value?.ToString();
yield return new PropertyInfo(VariantType.Nil, name, PropertyHint.None, hintString, propertyUsage.Value, true);
yield return new PropertyInfo(VariantType.Nil, name, PropertyHint.None, hintString,
propertyUsage.Value, true);
}
}
}

View file

@ -174,7 +174,8 @@ namespace Godot.SourceGenerators
}
else
{
var propertyGet = propertyDeclarationSyntax.AccessorList?.Accessors.Where(a => a.Keyword.IsKind(SyntaxKind.GetKeyword)).FirstOrDefault();
var propertyGet = propertyDeclarationSyntax.AccessorList?.Accessors
.Where(a => a.Keyword.IsKind(SyntaxKind.GetKeyword)).FirstOrDefault();
if (propertyGet != null)
{
if (propertyGet.ExpressionBody != null)
@ -200,7 +201,8 @@ namespace Godot.SourceGenerators
{
var returns = propertyGet.DescendantNodes().OfType<ReturnStatementSyntax>();
if (returns.Count() == 1)
{// Generate only single return
{
// Generate only single return
var returnStatementSyntax = returns.Single();
if (returnStatementSyntax.Expression is IdentifierNameSyntax identifierNameSyntax)
{
@ -277,7 +279,8 @@ namespace Godot.SourceGenerators
{
source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
string dictionaryType = "System.Collections.Generic.Dictionary<Godot.StringName, object>";
string dictionaryType =
"global::System.Collections.Generic.Dictionary<global::Godot.StringName, global::Godot.Variant>";
source.Append("#if TOOLS\n");
source.Append(" internal new static ");
@ -304,7 +307,8 @@ namespace Godot.SourceGenerators
source.Append(" values.Add(PropertyName.");
source.Append(exportedMember.Name);
source.Append(", ");
source.Append(defaultValueLocalName);
source.AppendManagedToVariantExpr(defaultValueLocalName,
exportedMember.TypeSymbol, exportedMember.Type);
source.Append(");\n");
}

View file

@ -162,7 +162,8 @@ namespace Godot.SourceGenerators
source.Append(" info.AddProperty(PropertyName.")
.Append(propertyName)
.Append(", ")
.AppendManagedToVariantExpr(string.Concat("this.", propertyName), property.Type)
.AppendManagedToVariantExpr(string.Concat("this.", propertyName),
property.PropertySymbol.Type, property.Type)
.Append(");\n");
}
@ -175,7 +176,8 @@ namespace Godot.SourceGenerators
source.Append(" info.AddProperty(PropertyName.")
.Append(fieldName)
.Append(", ")
.AppendManagedToVariantExpr(string.Concat("this.", fieldName), field.Type)
.AppendManagedToVariantExpr(string.Concat("this.", fieldName),
field.FieldSymbol.Type, field.Type)
.Append(");\n");
}

View file

@ -176,7 +176,8 @@ namespace Godot.SourceGenerators
source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
source.Append($" public new class SignalName : {symbol.BaseType.FullQualifiedNameIncludeGlobal()}.SignalName {{\n");
source.Append(
$" public new class SignalName : {symbol.BaseType.FullQualifiedNameIncludeGlobal()}.SignalName {{\n");
// Generate cached StringNames for methods and properties, for fast lookup
@ -236,7 +237,8 @@ namespace Godot.SourceGenerators
.Append(signalName)
.Append(";\n");
source.Append($" /// <inheritdoc cref=\"{signalDelegate.DelegateSymbol.FullQualifiedNameIncludeGlobal()}\"/>\n");
source.Append(
$" /// <inheritdoc cref=\"{signalDelegate.DelegateSymbol.FullQualifiedNameIncludeGlobal()}\"/>\n");
source.Append(" public event ")
.Append(signalDelegate.DelegateSymbol.FullQualifiedNameIncludeGlobal())
@ -351,7 +353,7 @@ namespace Godot.SourceGenerators
if (invokeMethodData.RetType != null)
{
returnVal = DeterminePropertyInfo(invokeMethodData.RetType.Value, name: string.Empty);
returnVal = DeterminePropertyInfo(invokeMethodData.RetType.Value.MarshalType, name: string.Empty);
}
else
{

View file

@ -455,7 +455,7 @@ namespace GodotTools
_menuPopup.IdPressed += _MenuOptionPressed;
// External editor settings
EditorDef("mono/editor/external_editor", ExternalEditorId.None);
EditorDef("mono/editor/external_editor", Variant.From(ExternalEditorId.None));
string settingsHintStr = "Disabled";

View file

@ -1,3 +1,4 @@
using Godot;
using Godot.NativeInterop;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
@ -8,30 +9,31 @@ namespace GodotTools.Internals
{
public static float EditorScale => Internal.godot_icall_Globals_EditorScale();
public static unsafe object GlobalDef(string setting, object defaultValue, bool restartIfChanged = false)
// ReSharper disable once UnusedMethodReturnValue.Global
public static Variant GlobalDef(string setting, Variant defaultValue, bool restartIfChanged = false)
{
using godot_string settingIn = Marshaling.ConvertStringToNative(setting);
using godot_variant defaultValueIn = Marshaling.ConvertManagedObjectToVariant(defaultValue);
Internal.godot_icall_Globals_GlobalDef(settingIn, defaultValueIn, restartIfChanged, out godot_variant result);
using (result)
return Marshaling.ConvertVariantToManagedObject(result);
using godot_variant defaultValueIn = defaultValue.CopyNativeVariant();
Internal.godot_icall_Globals_GlobalDef(settingIn, defaultValueIn, restartIfChanged,
out godot_variant result);
return Variant.CreateTakingOwnershipOfDisposableValue(result);
}
public static unsafe object EditorDef(string setting, object defaultValue, bool restartIfChanged = false)
// ReSharper disable once UnusedMethodReturnValue.Global
public static Variant EditorDef(string setting, Variant defaultValue, bool restartIfChanged = false)
{
using godot_string settingIn = Marshaling.ConvertStringToNative(setting);
using godot_variant defaultValueIn = Marshaling.ConvertManagedObjectToVariant(defaultValue);
Internal.godot_icall_Globals_EditorDef(settingIn, defaultValueIn, restartIfChanged, out godot_variant result);
using (result)
return Marshaling.ConvertVariantToManagedObject(result);
using godot_variant defaultValueIn = defaultValue.CopyNativeVariant();
Internal.godot_icall_Globals_EditorDef(settingIn, defaultValueIn, restartIfChanged,
out godot_variant result);
return Variant.CreateTakingOwnershipOfDisposableValue(result);
}
public static object EditorShortcut(string setting)
public static Variant EditorShortcut(string setting)
{
using godot_string settingIn = Marshaling.ConvertStringToNative(setting);
Internal.godot_icall_Globals_EditorShortcut(settingIn, out godot_variant result);
using (result)
return Marshaling.ConvertVariantToManagedObject(result);
return Variant.CreateTakingOwnershipOfDisposableValue(result);
}
[SuppressMessage("ReSharper", "InconsistentNaming")]

View file

@ -2837,9 +2837,6 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
itype.is_ref_counted = ClassDB::is_parent_class(type_cname, name_cache.type_RefCounted);
itype.memory_own = itype.is_ref_counted;
itype.cs_variant_to_managed = "(%1)VariantUtils.ConvertToGodotObject(%0)";
itype.cs_managed_to_variant = "VariantUtils.CreateFromGodotObject(%0)";
itype.c_out = "%5return ";
itype.c_out += C_METHOD_UNMANAGED_GET_MANAGED;
itype.c_out += itype.is_ref_counted ? "(%1.Reference);\n" : "(%1);\n";
@ -3218,8 +3215,6 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
enum_itype.cname = StringName(enum_itype.name);
enum_itype.proxy_name = itype.proxy_name + "." + enum_proxy_name;
TypeInterface::postsetup_enum_type(enum_itype);
enum_itype.cs_variant_to_managed = "(%1)VariantUtils.ConvertToInt32(%0)";
enum_itype.cs_managed_to_variant = "VariantUtils.CreateFromInt((int)%0)";
enum_types.insert(enum_itype.cname, enum_itype);
}
@ -3448,16 +3443,14 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
TypeInterface itype;
#define INSERT_STRUCT_TYPE(m_type) \
{ \
itype = TypeInterface::create_value_type(String(#m_type)); \
itype.c_type_in = #m_type "*"; \
itype.c_type_out = itype.cs_type; \
itype.cs_in_expr = "&%0"; \
itype.cs_in_expr_is_unsafe = true; \
itype.cs_variant_to_managed = "VariantUtils.ConvertTo%2(%0)"; \
itype.cs_managed_to_variant = "VariantUtils.CreateFrom%2(%0)"; \
builtin_types.insert(itype.cname, itype); \
#define INSERT_STRUCT_TYPE(m_type) \
{ \
itype = TypeInterface::create_value_type(String(#m_type)); \
itype.c_type_in = #m_type "*"; \
itype.c_type_out = itype.cs_type; \
itype.cs_in_expr = "&%0"; \
itype.cs_in_expr_is_unsafe = true; \
builtin_types.insert(itype.cname, itype); \
}
INSERT_STRUCT_TYPE(Vector2)
@ -3488,8 +3481,6 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.c_type_out = itype.c_type;
itype.c_arg_in = "&%s";
itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromBool(%1);\n";
itype.cs_variant_to_managed = "VariantUtils.ConvertToBool(%0)";
itype.cs_managed_to_variant = "VariantUtils.CreateFromBool(%0)";
builtin_types.insert(itype.cname, itype);
// Integer types
@ -3510,8 +3501,6 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.c_type_in = itype.name; \
itype.c_type_out = itype.name; \
itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromInt(%1);\n"; \
itype.cs_variant_to_managed = "VariantUtils.ConvertTo" m_int_struct_name "(%0)"; \
itype.cs_managed_to_variant = "VariantUtils.CreateFromInt(%0)"; \
builtin_types.insert(itype.cname, itype); \
}
@ -3547,8 +3536,6 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.c_type_in = itype.proxy_name;
itype.c_type_out = itype.proxy_name;
itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromFloat(%1);\n";
itype.cs_variant_to_managed = "VariantUtils.ConvertToFloat32(%0)";
itype.cs_managed_to_variant = "VariantUtils.CreateFromFloat(%0)";
builtin_types.insert(itype.cname, itype);
// double
@ -3562,8 +3549,6 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.c_type_in = itype.proxy_name;
itype.c_type_out = itype.proxy_name;
itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromFloat(%1);\n";
itype.cs_variant_to_managed = "VariantUtils.ConvertToFloat64(%0)";
itype.cs_managed_to_variant = "VariantUtils.CreateFromFloat(%0)";
builtin_types.insert(itype.cname, itype);
}
@ -3581,8 +3566,6 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.c_type_out = itype.cs_type;
itype.c_type_is_disposable_struct = true;
itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromString(%1);\n";
itype.cs_variant_to_managed = "VariantUtils.ConvertToStringObject(%0)";
itype.cs_managed_to_variant = "VariantUtils.CreateFromString(%0)";
builtin_types.insert(itype.cname, itype);
// StringName
@ -3601,8 +3584,6 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromStringName(%1);\n";
itype.c_type_is_disposable_struct = false; // [c_out] takes ownership
itype.c_ret_needs_default_initialization = true;
itype.cs_variant_to_managed = "VariantUtils.ConvertToStringNameObject(%0)";
itype.cs_managed_to_variant = "VariantUtils.CreateFromStringName(%0)";
builtin_types.insert(itype.cname, itype);
// NodePath
@ -3620,8 +3601,6 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.c_type_out = itype.cs_type;
itype.c_type_is_disposable_struct = false; // [c_out] takes ownership
itype.c_ret_needs_default_initialization = true;
itype.cs_variant_to_managed = "VariantUtils.ConvertToNodePathObject(%0)";
itype.cs_managed_to_variant = "VariantUtils.CreateFromNodePath(%0)";
builtin_types.insert(itype.cname, itype);
// RID
@ -3634,8 +3613,6 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.c_type = itype.cs_type;
itype.c_type_in = itype.c_type;
itype.c_type_out = itype.c_type;
itype.cs_variant_to_managed = "VariantUtils.ConvertToRID(%0)";
itype.cs_managed_to_variant = "VariantUtils.CreateFromRID(%0)";
builtin_types.insert(itype.cname, itype);
// Variant
@ -3652,8 +3629,6 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.c_type_out = itype.cs_type;
itype.c_type_is_disposable_struct = false; // [c_out] takes ownership
itype.c_ret_needs_default_initialization = true;
itype.cs_variant_to_managed = "Variant.CreateCopyingBorrowed(%0)";
itype.cs_managed_to_variant = "%0.CopyNativeVariant()";
builtin_types.insert(itype.cname, itype);
// Callable
@ -3666,8 +3641,6 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.c_type_in = "in " + itype.cs_type;
itype.c_type_out = itype.cs_type;
itype.c_type_is_disposable_struct = true;
itype.cs_variant_to_managed = "VariantUtils.ConvertToCallableManaged(%0)";
itype.cs_managed_to_variant = "VariantUtils.CreateFromCallable(%0)";
builtin_types.insert(itype.cname, itype);
// Signal
@ -3684,8 +3657,6 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.c_type_in = "in " + itype.cs_type;
itype.c_type_out = itype.cs_type;
itype.c_type_is_disposable_struct = true;
itype.cs_variant_to_managed = "VariantUtils.ConvertToSignalInfo(%0)";
itype.cs_managed_to_variant = "VariantUtils.CreateFromSignalInfo(%0)";
builtin_types.insert(itype.cname, itype);
// VarArg (fictitious type to represent variable arguments)
@ -3715,8 +3686,6 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.c_type_in = itype.proxy_name; \
itype.c_type_out = itype.proxy_name; \
itype.c_type_is_disposable_struct = true; \
itype.cs_variant_to_managed = "VariantUtils.ConvertAs%2ToSystemArray(%0)"; \
itype.cs_managed_to_variant = "VariantUtils.CreateFrom%2(%0)"; \
builtin_types.insert(itype.name, itype); \
}
@ -3752,8 +3721,6 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.c_type_out = itype.cs_type;
itype.c_type_is_disposable_struct = false; // [c_out] takes ownership
itype.c_ret_needs_default_initialization = true;
itype.cs_variant_to_managed = "VariantUtils.ConvertToArrayObject(%0)";
itype.cs_managed_to_variant = "VariantUtils.CreateFromArray(%0)";
builtin_types.insert(itype.cname, itype);
// Array_@generic
@ -3761,6 +3728,9 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.name = "Array_@generic";
itype.cname = itype.name;
itype.cs_out = "%5return new %2(%0(%1));";
// For generic Godot collections, Variant.From<T>/As<T> is slower, so we need this special case
itype.cs_variant_to_managed = "VariantUtils.ConvertToArrayObject(%0)";
itype.cs_managed_to_variant = "VariantUtils.CreateFromArray(%0)";
builtin_types.insert(itype.cname, itype);
// Dictionary
@ -3778,8 +3748,6 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.c_type_out = itype.cs_type;
itype.c_type_is_disposable_struct = false; // [c_out] takes ownership
itype.c_ret_needs_default_initialization = true;
itype.cs_variant_to_managed = "VariantUtils.ConvertToDictionaryObject(%0)";
itype.cs_managed_to_variant = "VariantUtils.CreateFromDictionary(%0)";
builtin_types.insert(itype.cname, itype);
// Dictionary_@generic
@ -3787,6 +3755,9 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.name = "Dictionary_@generic";
itype.cname = itype.name;
itype.cs_out = "%5return new %2(%0(%1));";
// For generic Godot collections, Variant.From<T>/As<T> is slower, so we need this special case
itype.cs_variant_to_managed = "VariantUtils.ConvertToDictionaryObject(%0)";
itype.cs_managed_to_variant = "VariantUtils.CreateFromDictionary(%0)";
builtin_types.insert(itype.cname, itype);
// void (fictitious type to represent the return type of methods that do not return anything)
@ -3852,8 +3823,6 @@ void BindingsGenerator::_populate_global_constants() {
enum_itype.cname = ienum.cname;
enum_itype.proxy_name = enum_itype.name;
TypeInterface::postsetup_enum_type(enum_itype);
enum_itype.cs_variant_to_managed = "(%1)VariantUtils.ConvertToInt32(%0)";
enum_itype.cs_managed_to_variant = "VariantUtils.CreateFromInt((int)%0)";
enum_types.insert(enum_itype.cname, enum_itype);
int prefix_length = _determine_enum_prefix(ienum);
@ -3886,8 +3855,6 @@ void BindingsGenerator::_populate_global_constants() {
enum_itype.cname = enum_cname;
enum_itype.proxy_name = enum_itype.name;
TypeInterface::postsetup_enum_type(enum_itype);
enum_itype.cs_variant_to_managed = "(%1)VariantUtils.ConvertToInt32(%0)";
enum_itype.cs_managed_to_variant = "VariantUtils.CreateFromInt((int)%0)";
enum_types.insert(enum_itype.cname, enum_itype);
}
}

View file

@ -209,7 +209,7 @@ class BindingsGenerator {
String name;
StringName cname;
int type_parameter_count;
int type_parameter_count = 0;
/**
* Identifier name of the base class.
@ -514,7 +514,12 @@ class BindingsGenerator {
static void postsetup_enum_type(TypeInterface &r_enum_itype);
TypeInterface() {}
TypeInterface() {
static String default_cs_variant_to_managed = "VariantUtils.ConvertTo<%1>(%0)";
static String default_cs_managed_to_variant = "VariantUtils.CreateFrom<%1>(%0)";
cs_variant_to_managed = default_cs_variant_to_managed;
cs_managed_to_variant = default_cs_managed_to_variant;
}
};
struct InternalCall {

View file

@ -418,8 +418,8 @@ namespace Godot.Collections
{
for (int i = 0; i < count; i++)
{
object obj = Marshaling.ConvertVariantToManagedObject(NativeValue.DangerousSelfRef.Elements[i]);
array.SetValue(obj, index);
object boxedVariant = Variant.CreateCopyingBorrowed(NativeValue.DangerousSelfRef.Elements[i]);
array.SetValue(boxedVariant, index);
index++;
}
}

View file

@ -159,7 +159,7 @@ namespace Godot.Bridge
for (int i = 0; i < paramCount; i++)
{
invokeParams[i] = Marshaling.ConvertVariantToManagedObjectOfType(
invokeParams[i] = DelegateUtils.RuntimeTypeConversionHelper.ConvertToObjectOfType(
*args[i], parameters[i].ParameterType);
}
@ -832,7 +832,8 @@ namespace Godot.Bridge
}
else
{
interopProperties = ((godotsharp_property_info*)NativeMemory.Alloc((nuint)length, (nuint)sizeof(godotsharp_property_info)))!;
interopProperties = ((godotsharp_property_info*)NativeMemory.Alloc(
(nuint)length, (nuint)sizeof(godotsharp_property_info)))!;
}
try
@ -858,8 +859,8 @@ namespace Godot.Bridge
addPropInfoFunc(scriptPtr, &currentClassName, interopProperties, length);
// We're borrowing the StringName's without making an owning copy, so the
// managed collection needs to be kept alive until `addPropInfoFunc` returns.
// We're borrowing the native value of the StringName entries.
// The dictionary needs to be kept alive until `addPropInfoFunc` returns.
GC.KeepAlive(properties);
}
finally
@ -884,12 +885,7 @@ namespace Godot.Bridge
{
// Careful with padding...
public godot_string_name Name; // Not owned
public godot_variant Value;
public void Dispose()
{
Value.Dispose();
}
public godot_variant Value; // Not owned
}
[UnmanagedCallersOnly]
@ -928,10 +924,35 @@ namespace Godot.Bridge
if (getGodotPropertyDefaultValuesMethod == null)
return;
var defaultValues = (Dictionary<StringName, object>?)
getGodotPropertyDefaultValuesMethod.Invoke(null, null);
var defaultValuesObj = getGodotPropertyDefaultValuesMethod.Invoke(null, null);
if (defaultValues == null || defaultValues.Count <= 0)
if (defaultValuesObj == null)
return;
Dictionary<StringName, Variant> defaultValues;
if (defaultValuesObj is Dictionary<StringName, object> defaultValuesLegacy)
{
// We have to support this for some time, otherwise this could cause data loss for projects
// built with previous releases. Ideally, we should remove this before Godot 4.0 stable.
if (defaultValuesLegacy.Count <= 0)
return;
defaultValues = new();
foreach (var pair in defaultValuesLegacy)
{
defaultValues[pair.Key] = Variant.CreateTakingOwnershipOfDisposableValue(
DelegateUtils.RuntimeTypeConversionHelper.ConvertToVariant(pair.Value));
}
}
else
{
defaultValues = (Dictionary<StringName, Variant>)defaultValuesObj;
}
if (defaultValues.Count <= 0)
return;
int length = defaultValues.Count;
@ -952,7 +973,8 @@ namespace Godot.Bridge
}
else
{
interopDefaultValues = ((godotsharp_property_def_val_pair*)NativeMemory.Alloc((nuint)length, (nuint)sizeof(godotsharp_property_def_val_pair)))!;
interopDefaultValues = ((godotsharp_property_def_val_pair*)NativeMemory.Alloc(
(nuint)length, (nuint)sizeof(godotsharp_property_def_val_pair)))!;
}
try
@ -963,7 +985,7 @@ namespace Godot.Bridge
godotsharp_property_def_val_pair interopProperty = new()
{
Name = (godot_string_name)defaultValuePair.Key.NativeValue, // Not owned
Value = Marshaling.ConvertManagedObjectToVariant(defaultValuePair.Value)
Value = (godot_variant)defaultValuePair.Value.NativeVar // Not owned
};
interopDefaultValues[i] = interopProperty;
@ -973,15 +995,12 @@ namespace Godot.Bridge
addDefValFunc(scriptPtr, interopDefaultValues, length);
// We're borrowing the StringName's without making an owning copy, so the
// managed collection needs to be kept alive until `addDefValFunc` returns.
// We're borrowing the native value of the StringName and Variant entries.
// The dictionary needs to be kept alive until `addDefValFunc` returns.
GC.KeepAlive(defaultValues);
}
finally
{
for (int i = 0; i < length; i++)
interopDefaultValues[i].Dispose();
if (!useStack)
NativeMemory.Free(interopDefaultValues);
}

View file

@ -186,7 +186,7 @@ namespace Godot
writer.Write(field.Name);
var fieldValue = field.GetValue(target);
using var fieldValueVariant = Marshaling.ConvertManagedObjectToVariant(fieldValue);
using var fieldValueVariant = RuntimeTypeConversionHelper.ConvertToVariant(fieldValue);
byte[] valueBuffer = VarToBytes(fieldValueVariant);
writer.Write(valueBuffer.Length);
writer.Write(valueBuffer);
@ -443,7 +443,14 @@ namespace Godot
FieldInfo? fieldInfo = targetType.GetField(name,
BindingFlags.Instance | BindingFlags.Public);
fieldInfo?.SetValue(recreatedTarget, GD.BytesToVar(valueBuffer));
if (fieldInfo != null)
{
var variantValue = GD.BytesToVar(valueBuffer);
object? managedValue = RuntimeTypeConversionHelper.ConvertToObjectOfType(
(godot_variant)variantValue.NativeVar, fieldInfo.FieldType);
fieldInfo.SetValue(recreatedTarget, managedValue);
}
}
@delegate = Delegate.CreateDelegate(delegateType, recreatedTarget, methodInfo,
@ -537,5 +544,269 @@ namespace Godot
return type;
}
internal static class RuntimeTypeConversionHelper
{
[SuppressMessage("ReSharper", "RedundantNameQualifier")]
public static godot_variant ConvertToVariant(object? obj)
{
if (obj == null)
return default;
switch (obj)
{
case bool @bool:
return VariantUtils.CreateFrom(@bool);
case char @char:
return VariantUtils.CreateFrom(@char);
case sbyte int8:
return VariantUtils.CreateFrom(int8);
case short int16:
return VariantUtils.CreateFrom(int16);
case int int32:
return VariantUtils.CreateFrom(int32);
case long int64:
return VariantUtils.CreateFrom(int64);
case byte uint8:
return VariantUtils.CreateFrom(uint8);
case ushort uint16:
return VariantUtils.CreateFrom(uint16);
case uint uint32:
return VariantUtils.CreateFrom(uint32);
case ulong uint64:
return VariantUtils.CreateFrom(uint64);
case float @float:
return VariantUtils.CreateFrom(@float);
case double @double:
return VariantUtils.CreateFrom(@double);
case Vector2 vector2:
return VariantUtils.CreateFrom(vector2);
case Vector2i vector2I:
return VariantUtils.CreateFrom(vector2I);
case Rect2 rect2:
return VariantUtils.CreateFrom(rect2);
case Rect2i rect2I:
return VariantUtils.CreateFrom(rect2I);
case Transform2D transform2D:
return VariantUtils.CreateFrom(transform2D);
case Vector3 vector3:
return VariantUtils.CreateFrom(vector3);
case Vector3i vector3I:
return VariantUtils.CreateFrom(vector3I);
case Vector4 vector4:
return VariantUtils.CreateFrom(vector4);
case Vector4i vector4I:
return VariantUtils.CreateFrom(vector4I);
case Basis basis:
return VariantUtils.CreateFrom(basis);
case Quaternion quaternion:
return VariantUtils.CreateFrom(quaternion);
case Transform3D transform3d:
return VariantUtils.CreateFrom(transform3d);
case Projection projection:
return VariantUtils.CreateFrom(projection);
case AABB aabb:
return VariantUtils.CreateFrom(aabb);
case Color color:
return VariantUtils.CreateFrom(color);
case Plane plane:
return VariantUtils.CreateFrom(plane);
case Callable callable:
return VariantUtils.CreateFrom(callable);
case SignalInfo signalInfo:
return VariantUtils.CreateFrom(signalInfo);
case string @string:
return VariantUtils.CreateFrom(@string);
case byte[] byteArray:
return VariantUtils.CreateFrom(byteArray);
case int[] int32Array:
return VariantUtils.CreateFrom(int32Array);
case long[] int64Array:
return VariantUtils.CreateFrom(int64Array);
case float[] floatArray:
return VariantUtils.CreateFrom(floatArray);
case double[] doubleArray:
return VariantUtils.CreateFrom(doubleArray);
case string[] stringArray:
return VariantUtils.CreateFrom(stringArray);
case Vector2[] vector2Array:
return VariantUtils.CreateFrom(vector2Array);
case Vector3[] vector3Array:
return VariantUtils.CreateFrom(vector3Array);
case Color[] colorArray:
return VariantUtils.CreateFrom(colorArray);
case StringName[] stringNameArray:
return VariantUtils.CreateFrom(stringNameArray);
case NodePath[] nodePathArray:
return VariantUtils.CreateFrom(nodePathArray);
case RID[] ridArray:
return VariantUtils.CreateFrom(ridArray);
case Godot.Object[] godotObjectArray:
return VariantUtils.CreateFrom(godotObjectArray);
case StringName stringName:
return VariantUtils.CreateFrom(stringName);
case NodePath nodePath:
return VariantUtils.CreateFrom(nodePath);
case RID rid:
return VariantUtils.CreateFrom(rid);
case Collections.Dictionary godotDictionary:
return VariantUtils.CreateFrom(godotDictionary);
case Collections.Array godotArray:
return VariantUtils.CreateFrom(godotArray);
case Variant variant:
return VariantUtils.CreateFrom(variant);
case Godot.Object godotObject:
return VariantUtils.CreateFrom(godotObject);
case Enum @enum:
return VariantUtils.CreateFrom(Convert.ToInt64(@enum));
case Collections.IGenericGodotDictionary godotDictionary:
return VariantUtils.CreateFrom(godotDictionary.UnderlyingDictionary);
case Collections.IGenericGodotArray godotArray:
return VariantUtils.CreateFrom(godotArray.UnderlyingArray);
}
GD.PushError("Attempted to convert an unmarshallable managed type to Variant. Name: '" +
obj.GetType().FullName + ".");
return new godot_variant();
}
private delegate object? ConvertToSystemObjectFunc(in godot_variant managed);
[SuppressMessage("ReSharper", "RedundantNameQualifier")]
// ReSharper disable once RedundantNameQualifier
private static readonly System.Collections.Generic.Dictionary<Type, ConvertToSystemObjectFunc>
ToSystemObjectFuncByType = new()
{
[typeof(bool)] = (in godot_variant variant) => VariantUtils.ConvertTo<bool>(variant),
[typeof(char)] = (in godot_variant variant) => VariantUtils.ConvertTo<char>(variant),
[typeof(sbyte)] = (in godot_variant variant) => VariantUtils.ConvertTo<sbyte>(variant),
[typeof(short)] = (in godot_variant variant) => VariantUtils.ConvertTo<short>(variant),
[typeof(int)] = (in godot_variant variant) => VariantUtils.ConvertTo<int>(variant),
[typeof(long)] = (in godot_variant variant) => VariantUtils.ConvertTo<long>(variant),
[typeof(byte)] = (in godot_variant variant) => VariantUtils.ConvertTo<byte>(variant),
[typeof(ushort)] = (in godot_variant variant) => VariantUtils.ConvertTo<ushort>(variant),
[typeof(uint)] = (in godot_variant variant) => VariantUtils.ConvertTo<uint>(variant),
[typeof(ulong)] = (in godot_variant variant) => VariantUtils.ConvertTo<ulong>(variant),
[typeof(float)] = (in godot_variant variant) => VariantUtils.ConvertTo<float>(variant),
[typeof(double)] = (in godot_variant variant) => VariantUtils.ConvertTo<double>(variant),
[typeof(Vector2)] = (in godot_variant variant) => VariantUtils.ConvertTo<Vector2>(variant),
[typeof(Vector2i)] = (in godot_variant variant) => VariantUtils.ConvertTo<Vector2i>(variant),
[typeof(Rect2)] = (in godot_variant variant) => VariantUtils.ConvertTo<Rect2>(variant),
[typeof(Rect2i)] = (in godot_variant variant) => VariantUtils.ConvertTo<Rect2i>(variant),
[typeof(Transform2D)] = (in godot_variant variant) => VariantUtils.ConvertTo<Transform2D>(variant),
[typeof(Vector3)] = (in godot_variant variant) => VariantUtils.ConvertTo<Vector3>(variant),
[typeof(Vector3i)] = (in godot_variant variant) => VariantUtils.ConvertTo<Vector3i>(variant),
[typeof(Basis)] = (in godot_variant variant) => VariantUtils.ConvertTo<Basis>(variant),
[typeof(Quaternion)] = (in godot_variant variant) => VariantUtils.ConvertTo<Quaternion>(variant),
[typeof(Transform3D)] = (in godot_variant variant) => VariantUtils.ConvertTo<Transform3D>(variant),
[typeof(Vector4)] = (in godot_variant variant) => VariantUtils.ConvertTo<Vector4>(variant),
[typeof(Vector4i)] = (in godot_variant variant) => VariantUtils.ConvertTo<Vector4i>(variant),
[typeof(AABB)] = (in godot_variant variant) => VariantUtils.ConvertTo<AABB>(variant),
[typeof(Color)] = (in godot_variant variant) => VariantUtils.ConvertTo<Color>(variant),
[typeof(Plane)] = (in godot_variant variant) => VariantUtils.ConvertTo<Plane>(variant),
[typeof(Callable)] = (in godot_variant variant) => VariantUtils.ConvertTo<Callable>(variant),
[typeof(SignalInfo)] = (in godot_variant variant) => VariantUtils.ConvertTo<SignalInfo>(variant),
[typeof(string)] = (in godot_variant variant) => VariantUtils.ConvertTo<string>(variant),
[typeof(byte[])] = (in godot_variant variant) => VariantUtils.ConvertTo<byte[]>(variant),
[typeof(int[])] = (in godot_variant variant) => VariantUtils.ConvertTo<int[]>(variant),
[typeof(long[])] = (in godot_variant variant) => VariantUtils.ConvertTo<long[]>(variant),
[typeof(float[])] = (in godot_variant variant) => VariantUtils.ConvertTo<float[]>(variant),
[typeof(double[])] = (in godot_variant variant) => VariantUtils.ConvertTo<double[]>(variant),
[typeof(string[])] = (in godot_variant variant) => VariantUtils.ConvertTo<string[]>(variant),
[typeof(Vector2[])] = (in godot_variant variant) => VariantUtils.ConvertTo<Vector2[]>(variant),
[typeof(Vector3[])] = (in godot_variant variant) => VariantUtils.ConvertTo<Vector3[]>(variant),
[typeof(Color[])] = (in godot_variant variant) => VariantUtils.ConvertTo<Color[]>(variant),
[typeof(StringName[])] =
(in godot_variant variant) => VariantUtils.ConvertTo<StringName[]>(variant),
[typeof(NodePath[])] = (in godot_variant variant) => VariantUtils.ConvertTo<NodePath[]>(variant),
[typeof(RID[])] = (in godot_variant variant) => VariantUtils.ConvertTo<RID[]>(variant),
[typeof(StringName)] = (in godot_variant variant) => VariantUtils.ConvertTo<StringName>(variant),
[typeof(NodePath)] = (in godot_variant variant) => VariantUtils.ConvertTo<NodePath>(variant),
[typeof(RID)] = (in godot_variant variant) => VariantUtils.ConvertTo<RID>(variant),
[typeof(Godot.Collections.Dictionary)] = (in godot_variant variant) =>
VariantUtils.ConvertTo<Godot.Collections.Dictionary>(variant),
[typeof(Godot.Collections.Array)] =
(in godot_variant variant) => VariantUtils.ConvertTo<Godot.Collections.Array>(variant),
[typeof(Variant)] = (in godot_variant variant) => VariantUtils.ConvertTo<Variant>(variant),
};
[SuppressMessage("ReSharper", "RedundantNameQualifier")]
public static object? ConvertToObjectOfType(in godot_variant variant, Type type)
{
if (ToSystemObjectFuncByType.TryGetValue(type, out var func))
return func(variant);
if (typeof(Godot.Object).IsAssignableFrom(type))
return Convert.ChangeType(VariantUtils.ConvertTo<Godot.Object>(variant), type);
if (type.IsEnum)
{
var enumUnderlyingType = type.GetEnumUnderlyingType();
switch (Type.GetTypeCode(enumUnderlyingType))
{
case TypeCode.SByte:
return Enum.ToObject(type, VariantUtils.ConvertToInt8(variant));
case TypeCode.Int16:
return Enum.ToObject(type, VariantUtils.ConvertToInt16(variant));
case TypeCode.Int32:
return Enum.ToObject(type, VariantUtils.ConvertToInt32(variant));
case TypeCode.Int64:
return Enum.ToObject(type, VariantUtils.ConvertToInt64(variant));
case TypeCode.Byte:
return Enum.ToObject(type, VariantUtils.ConvertToUInt8(variant));
case TypeCode.UInt16:
return Enum.ToObject(type, VariantUtils.ConvertToUInt16(variant));
case TypeCode.UInt32:
return Enum.ToObject(type, VariantUtils.ConvertToUInt32(variant));
case TypeCode.UInt64:
return Enum.ToObject(type, VariantUtils.ConvertToUInt64(variant));
default:
{
GD.PushError(
"Attempted to convert Variant to enum value of unsupported underlying type. Name: " +
type.FullName + " : " + enumUnderlyingType.FullName + ".");
return null;
}
}
}
if (type.IsGenericType)
{
var genericTypeDef = type.GetGenericTypeDefinition();
if (genericTypeDef == typeof(Godot.Collections.Dictionary<,>))
{
var ctor = type.GetConstructor(BindingFlags.Default,
new[] { typeof(Godot.Collections.Dictionary) });
if (ctor == null)
throw new InvalidOperationException("Dictionary constructor not found");
return ctor.Invoke(new object?[]
{
VariantUtils.ConvertTo<Godot.Collections.Dictionary>(variant)
});
}
if (genericTypeDef == typeof(Godot.Collections.Array<>))
{
var ctor = type.GetConstructor(BindingFlags.Default,
new[] { typeof(Godot.Collections.Array) });
if (ctor == null)
throw new InvalidOperationException("Array constructor not found");
return ctor.Invoke(new object?[]
{
VariantUtils.ConvertTo<Godot.Collections.Array>(variant)
});
}
}
GD.PushError($"Attempted to convert Variant to unsupported type. Name: {type.FullName}.");
return null;
}
}
}
}

View file

@ -1,5 +1,7 @@
using System;
using System.Runtime.InteropServices;
using Godot.Collections;
using Array = System.Array;
// ReSharper disable InconsistentNaming
@ -148,6 +150,15 @@ namespace Godot.NativeInterop
{
if (typeof(Godot.Object).IsAssignableFrom(type))
return Variant.Type.Object;
// We use `IsAssignableFrom` with our helper interfaces to detect generic Godot collections
// because `GetGenericTypeDefinition` is not supported in NativeAOT reflection-free mode.
if (typeof(IGenericGodotDictionary).IsAssignableFrom(type))
return Variant.Type.Dictionary;
if (typeof(IGenericGodotArray).IsAssignableFrom(type))
return Variant.Type.Array;
}
else if (type == typeof(Variant))
{
@ -183,512 +194,6 @@ namespace Godot.NativeInterop
return Variant.Type.Nil;
}
/* 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)
return new godot_variant();
switch (p_obj)
{
case bool @bool:
return VariantUtils.CreateFromBool(@bool);
case char @char:
return VariantUtils.CreateFromInt(@char);
case sbyte @int8:
return VariantUtils.CreateFromInt(@int8);
case short @int16:
return VariantUtils.CreateFromInt(@int16);
case int @int32:
return VariantUtils.CreateFromInt(@int32);
case long @int64:
return VariantUtils.CreateFromInt(@int64);
case byte @uint8:
return VariantUtils.CreateFromInt(@uint8);
case ushort @uint16:
return VariantUtils.CreateFromInt(@uint16);
case uint @uint32:
return VariantUtils.CreateFromInt(@uint32);
case ulong @uint64:
return VariantUtils.CreateFromInt(@uint64);
case float @float:
return VariantUtils.CreateFromFloat(@float);
case double @double:
return VariantUtils.CreateFromFloat(@double);
case Vector2 @vector2:
return VariantUtils.CreateFromVector2(@vector2);
case Vector2i @vector2i:
return VariantUtils.CreateFromVector2i(@vector2i);
case Rect2 @rect2:
return VariantUtils.CreateFromRect2(@rect2);
case Rect2i @rect2i:
return VariantUtils.CreateFromRect2i(@rect2i);
case Transform2D @transform2D:
return VariantUtils.CreateFromTransform2D(@transform2D);
case Vector3 @vector3:
return VariantUtils.CreateFromVector3(@vector3);
case Vector3i @vector3i:
return VariantUtils.CreateFromVector3i(@vector3i);
case Vector4 @vector4:
return VariantUtils.CreateFromVector4(@vector4);
case Vector4i @vector4i:
return VariantUtils.CreateFromVector4i(@vector4i);
case Basis @basis:
return VariantUtils.CreateFromBasis(@basis);
case Quaternion @quaternion:
return VariantUtils.CreateFromQuaternion(@quaternion);
case Transform3D @transform3d:
return VariantUtils.CreateFromTransform3D(@transform3d);
case Projection @projection:
return VariantUtils.CreateFromProjection(@projection);
case AABB @aabb:
return VariantUtils.CreateFromAABB(@aabb);
case Color @color:
return VariantUtils.CreateFromColor(@color);
case Plane @plane:
return VariantUtils.CreateFromPlane(@plane);
case Callable @callable:
return VariantUtils.CreateFromCallable(@callable);
case SignalInfo @signalInfo:
return VariantUtils.CreateFromSignalInfo(@signalInfo);
case Enum @enum:
return VariantUtils.CreateFromInt(Convert.ToInt64(@enum));
case string @string:
return VariantUtils.CreateFromString(@string);
case byte[] byteArray:
return VariantUtils.CreateFromPackedByteArray(byteArray);
case int[] int32Array:
return VariantUtils.CreateFromPackedInt32Array(int32Array);
case long[] int64Array:
return VariantUtils.CreateFromPackedInt64Array(int64Array);
case float[] floatArray:
return VariantUtils.CreateFromPackedFloat32Array(floatArray);
case double[] doubleArray:
return VariantUtils.CreateFromPackedFloat64Array(doubleArray);
case string[] stringArray:
return VariantUtils.CreateFromPackedStringArray(stringArray);
case Vector2[] vector2Array:
return VariantUtils.CreateFromPackedVector2Array(vector2Array);
case Vector3[] vector3Array:
return VariantUtils.CreateFromPackedVector3Array(vector3Array);
case Color[] colorArray:
return VariantUtils.CreateFromPackedColorArray(colorArray);
case StringName[] stringNameArray:
return VariantUtils.CreateFromSystemArrayOfStringName(stringNameArray);
case NodePath[] nodePathArray:
return VariantUtils.CreateFromSystemArrayOfNodePath(nodePathArray);
case RID[] ridArray:
return VariantUtils.CreateFromSystemArrayOfRID(ridArray);
case Godot.Object[] godotObjectArray:
return VariantUtils.CreateFromSystemArrayOfGodotObject(godotObjectArray);
case Godot.Object godotObject:
return VariantUtils.CreateFromGodotObject(godotObject);
case StringName stringName:
return VariantUtils.CreateFromStringName(stringName);
case NodePath nodePath:
return VariantUtils.CreateFromNodePath(nodePath);
case RID rid:
return VariantUtils.CreateFromRID(rid);
case Collections.Dictionary godotDictionary:
return VariantUtils.CreateFromDictionary(godotDictionary);
case Collections.Array godotArray:
return VariantUtils.CreateFromArray(godotArray);
case Collections.IGenericGodotDictionary godotDictionary:
return VariantUtils.CreateFromDictionary(godotDictionary.UnderlyingDictionary);
case Collections.IGenericGodotArray godotArray:
return VariantUtils.CreateFromArray(godotArray.UnderlyingArray);
case Variant variant:
return NativeFuncs.godotsharp_variant_new_copy((godot_variant)variant.NativeVar);
}
GD.PushError("Attempted to convert an unmarshallable managed type to Variant. Name: '" +
p_obj.GetType().FullName + ".");
return new godot_variant();
}
public static object? ConvertVariantToManagedObjectOfType(in godot_variant p_var, Type type)
{
// This function is only needed to set the value of properties. Fields have their own implementation, set_value_from_variant.
switch (Type.GetTypeCode(type))
{
case TypeCode.Boolean:
return VariantUtils.ConvertToBool(p_var);
case TypeCode.Char:
return VariantUtils.ConvertToChar(p_var);
case TypeCode.SByte:
return VariantUtils.ConvertToInt8(p_var);
case TypeCode.Int16:
return VariantUtils.ConvertToInt16(p_var);
case TypeCode.Int32:
return VariantUtils.ConvertToInt32(p_var);
case TypeCode.Int64:
return VariantUtils.ConvertToInt64(p_var);
case TypeCode.Byte:
return VariantUtils.ConvertToUInt8(p_var);
case TypeCode.UInt16:
return VariantUtils.ConvertToUInt16(p_var);
case TypeCode.UInt32:
return VariantUtils.ConvertToUInt32(p_var);
case TypeCode.UInt64:
return VariantUtils.ConvertToUInt64(p_var);
case TypeCode.Single:
return VariantUtils.ConvertToFloat32(p_var);
case TypeCode.Double:
return VariantUtils.ConvertToFloat64(p_var);
case TypeCode.String:
return VariantUtils.ConvertToStringObject(p_var);
default:
{
if (type == typeof(Vector2))
return VariantUtils.ConvertToVector2(p_var);
if (type == typeof(Vector2i))
return VariantUtils.ConvertToVector2i(p_var);
if (type == typeof(Rect2))
return VariantUtils.ConvertToRect2(p_var);
if (type == typeof(Rect2i))
return VariantUtils.ConvertToRect2i(p_var);
if (type == typeof(Transform2D))
return VariantUtils.ConvertToTransform2D(p_var);
if (type == typeof(Vector3))
return VariantUtils.ConvertToVector3(p_var);
if (type == typeof(Vector3i))
return VariantUtils.ConvertToVector3i(p_var);
if (type == typeof(Vector4))
return VariantUtils.ConvertToVector4(p_var);
if (type == typeof(Vector4i))
return VariantUtils.ConvertToVector4i(p_var);
if (type == typeof(Basis))
return VariantUtils.ConvertToBasis(p_var);
if (type == typeof(Quaternion))
return VariantUtils.ConvertToQuaternion(p_var);
if (type == typeof(Transform3D))
return VariantUtils.ConvertToTransform3D(p_var);
if (type == typeof(Projection))
return VariantUtils.ConvertToProjection(p_var);
if (type == typeof(AABB))
return VariantUtils.ConvertToAABB(p_var);
if (type == typeof(Color))
return VariantUtils.ConvertToColor(p_var);
if (type == typeof(Plane))
return VariantUtils.ConvertToPlane(p_var);
if (type == typeof(Callable))
return VariantUtils.ConvertToCallableManaged(p_var);
if (type == typeof(SignalInfo))
return VariantUtils.ConvertToSignalInfo(p_var);
if (type.IsEnum)
{
var enumUnderlyingType = type.GetEnumUnderlyingType();
switch (Type.GetTypeCode(enumUnderlyingType))
{
case TypeCode.SByte:
return VariantUtils.ConvertToInt8(p_var);
case TypeCode.Int16:
return VariantUtils.ConvertToInt16(p_var);
case TypeCode.Int32:
return VariantUtils.ConvertToInt32(p_var);
case TypeCode.Int64:
return VariantUtils.ConvertToInt64(p_var);
case TypeCode.Byte:
return VariantUtils.ConvertToUInt8(p_var);
case TypeCode.UInt16:
return VariantUtils.ConvertToUInt16(p_var);
case TypeCode.UInt32:
return VariantUtils.ConvertToUInt32(p_var);
case TypeCode.UInt64:
return VariantUtils.ConvertToUInt64(p_var);
default:
{
GD.PushError(
"Attempted to convert Variant to enum value of unsupported underlying type. Name: " +
type.FullName + " : " + enumUnderlyingType.FullName + ".");
return null;
}
}
}
if (type.IsArray || type.IsSZArray)
{
return ConvertVariantToSystemArrayOfType(p_var, type);
}
else if (type.IsGenericType)
{
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;
break;
}
}
GD.PushError("Attempted to convert Variant to unsupported type. Name: " +
type.FullName + ".");
return null;
}
private static object? ConvertVariantToSystemArrayOfType(in godot_variant p_var, Type type)
{
if (type == typeof(byte[]))
return VariantUtils.ConvertAsPackedByteArrayToSystemArray(p_var);
if (type == typeof(int[]))
return VariantUtils.ConvertAsPackedInt32ArrayToSystemArray(p_var);
if (type == typeof(long[]))
return VariantUtils.ConvertAsPackedInt64ArrayToSystemArray(p_var);
if (type == typeof(float[]))
return VariantUtils.ConvertAsPackedFloat32ArrayToSystemArray(p_var);
if (type == typeof(double[]))
return VariantUtils.ConvertAsPackedFloat64ArrayToSystemArray(p_var);
if (type == typeof(string[]))
return VariantUtils.ConvertAsPackedStringArrayToSystemArray(p_var);
if (type == typeof(Vector2[]))
return VariantUtils.ConvertAsPackedVector2ArrayToSystemArray(p_var);
if (type == typeof(Vector3[]))
return VariantUtils.ConvertAsPackedVector3ArrayToSystemArray(p_var);
if (type == typeof(Color[]))
return VariantUtils.ConvertAsPackedColorArrayToSystemArray(p_var);
if (type == typeof(StringName[]))
return VariantUtils.ConvertToSystemArrayOfStringName(p_var);
if (type == typeof(NodePath[]))
return VariantUtils.ConvertToSystemArrayOfNodePath(p_var);
if (type == typeof(RID[]))
return VariantUtils.ConvertToSystemArrayOfRID(p_var);
if (typeof(Godot.Object[]).IsAssignableFrom(type))
return VariantUtils.ConvertToSystemArrayOfGodotObject(p_var, type);
GD.PushError("Attempted to convert Variant to array of unsupported element type. Name: " +
type.GetElementType()!.FullName + ".");
return null;
}
private static bool ConvertVariantToManagedObjectOfClass(in godot_variant p_var, Type type,
out object? res)
{
if (typeof(Godot.Object).IsAssignableFrom(type))
{
if (p_var.Type == Variant.Type.Nil)
{
res = null;
return true;
}
if (p_var.Type != Variant.Type.Object)
{
GD.PushError("Invalid cast when marshaling Godot.Object type." +
$" Variant type is `{p_var.Type}`; expected `{p_var.Object}`.");
res = null;
return true;
}
var godotObjectPtr = VariantUtils.ConvertToGodotObjectPtr(p_var);
if (godotObjectPtr == IntPtr.Zero)
{
res = null;
return true;
}
var godotObject = InteropUtils.UnmanagedGetManaged(godotObjectPtr);
if (!type.IsInstanceOfType(godotObject))
{
GD.PushError("Invalid cast when marshaling Godot.Object type." +
$" `{godotObject.GetType()}` is not assignable to `{type.FullName}`.");
res = null;
return false;
}
res = godotObject;
return true;
}
if (typeof(StringName) == type)
{
res = VariantUtils.ConvertToStringNameObject(p_var);
return true;
}
if (typeof(NodePath) == type)
{
res = VariantUtils.ConvertToNodePathObject(p_var);
return true;
}
if (typeof(RID) == type)
{
res = VariantUtils.ConvertToRID(p_var);
return true;
}
if (typeof(Collections.Dictionary) == type)
{
res = VariantUtils.ConvertToDictionaryObject(p_var);
return true;
}
if (typeof(Collections.Array) == type)
{
res = VariantUtils.ConvertToArrayObject(p_var);
return true;
}
res = null;
return false;
}
public static unsafe object? ConvertVariantToManagedObject(in godot_variant p_var)
{
switch (p_var.Type)
{
case Variant.Type.Bool:
return p_var.Bool.ToBool();
case Variant.Type.Int:
return p_var.Int;
case Variant.Type.Float:
{
#if REAL_T_IS_DOUBLE
return p_var.Float;
#else
return (float)p_var.Float;
#endif
}
case Variant.Type.String:
return ConvertStringToManaged(p_var.String);
case Variant.Type.Vector2:
return p_var.Vector2;
case Variant.Type.Vector2i:
return p_var.Vector2i;
case Variant.Type.Rect2:
return p_var.Rect2;
case Variant.Type.Rect2i:
return p_var.Rect2i;
case Variant.Type.Vector3:
return p_var.Vector3;
case Variant.Type.Vector3i:
return p_var.Vector3i;
case Variant.Type.Transform2d:
return *p_var.Transform2D;
case Variant.Type.Vector4:
return p_var.Vector4;
case Variant.Type.Vector4i:
return p_var.Vector4i;
case Variant.Type.Plane:
return p_var.Plane;
case Variant.Type.Quaternion:
return p_var.Quaternion;
case Variant.Type.Aabb:
return *p_var.AABB;
case Variant.Type.Basis:
return *p_var.Basis;
case Variant.Type.Transform3d:
return *p_var.Transform3D;
case Variant.Type.Projection:
return *p_var.Projection;
case Variant.Type.Color:
return p_var.Color;
case Variant.Type.StringName:
{
// The Variant owns the value, so we need to make a copy
return StringName.CreateTakingOwnershipOfDisposableValue(
NativeFuncs.godotsharp_string_name_new_copy(p_var.StringName));
}
case Variant.Type.NodePath:
{
// The Variant owns the value, so we need to make a copy
return NodePath.CreateTakingOwnershipOfDisposableValue(
NativeFuncs.godotsharp_node_path_new_copy(p_var.NodePath));
}
case Variant.Type.Rid:
return p_var.RID;
case Variant.Type.Object:
return InteropUtils.UnmanagedGetManaged(p_var.Object);
case Variant.Type.Callable:
return ConvertCallableToManaged(p_var.Callable);
case Variant.Type.Signal:
return ConvertSignalToManaged(p_var.Signal);
case Variant.Type.Dictionary:
{
// The Variant owns the value, so we need to make a copy
return Collections.Dictionary.CreateTakingOwnershipOfDisposableValue(
NativeFuncs.godotsharp_dictionary_new_copy(p_var.Dictionary));
}
case Variant.Type.Array:
{
// The Variant owns the value, so we need to make a copy
return Collections.Array.CreateTakingOwnershipOfDisposableValue(
NativeFuncs.godotsharp_array_new_copy(p_var.Array));
}
case Variant.Type.PackedByteArray:
return VariantUtils.ConvertAsPackedByteArrayToSystemArray(p_var);
case Variant.Type.PackedInt32Array:
return VariantUtils.ConvertAsPackedInt32ArrayToSystemArray(p_var);
case Variant.Type.PackedInt64Array:
return VariantUtils.ConvertAsPackedInt64ArrayToSystemArray(p_var);
case Variant.Type.PackedFloat32Array:
return VariantUtils.ConvertAsPackedFloat32ArrayToSystemArray(p_var);
case Variant.Type.PackedFloat64Array:
return VariantUtils.ConvertAsPackedFloat64ArrayToSystemArray(p_var);
case Variant.Type.PackedStringArray:
return VariantUtils.ConvertAsPackedStringArrayToSystemArray(p_var);
case Variant.Type.PackedVector2Array:
return VariantUtils.ConvertAsPackedVector2ArrayToSystemArray(p_var);
case Variant.Type.PackedVector3Array:
return VariantUtils.ConvertAsPackedVector3ArrayToSystemArray(p_var);
case Variant.Type.PackedColorArray:
return VariantUtils.ConvertAsPackedColorArrayToSystemArray(p_var);
default:
return null;
}
}
// String
public static unsafe godot_string ConvertStringToNative(string? p_mono_string)

View file

@ -4,6 +4,8 @@ using System.Runtime.CompilerServices;
namespace Godot.NativeInterop;
#nullable enable
public partial class VariantUtils
{
private static Exception UnsupportedType<T>() => new InvalidOperationException(

View file

@ -109,16 +109,54 @@ public partial struct Variant : IDisposable
public override string ToString() => AsString();
public object? Obj
{
get
public object? Obj =>
_obj ??= NativeVar.DangerousSelfRef.Type switch
{
if (_obj == null)
_obj = Marshaling.ConvertVariantToManagedObject((godot_variant)NativeVar);
return _obj;
}
}
Type.Bool => AsBool(),
Type.Int => AsInt64(),
#if REAL_T_IS_DOUBLE
Type.Float => AsDouble(),
#else
Type.Float => AsSingle(),
#endif
Type.String => AsString(),
Type.Vector2 => AsVector2(),
Type.Vector2i => AsVector2i(),
Type.Rect2 => AsRect2(),
Type.Rect2i => AsRect2i(),
Type.Vector3 => AsVector3(),
Type.Vector3i => AsVector3i(),
Type.Transform2d => AsTransform2D(),
Type.Vector4 => AsVector4(),
Type.Vector4i => AsVector4i(),
Type.Plane => AsPlane(),
Type.Quaternion => AsQuaternion(),
Type.Aabb => AsAABB(),
Type.Basis => AsBasis(),
Type.Transform3d => AsTransform3D(),
Type.Projection => AsProjection(),
Type.Color => AsColor(),
Type.StringName => AsStringName(),
Type.NodePath => AsNodePath(),
Type.Rid => AsRID(),
Type.Object => AsGodotObject(),
Type.Callable => AsCallable(),
Type.Signal => AsSignalInfo(),
Type.Dictionary => AsGodotDictionary(),
Type.Array => AsGodotArray(),
Type.PackedByteArray => AsByteArray(),
Type.PackedInt32Array => AsInt32Array(),
Type.PackedInt64Array => AsInt64Array(),
Type.PackedFloat32Array => AsFloat32Array(),
Type.PackedFloat64Array => AsFloat64Array(),
Type.PackedStringArray => AsStringArray(),
Type.PackedVector2Array => AsVector2Array(),
Type.PackedVector3Array => AsVector3Array(),
Type.PackedColorArray => AsColorArray(),
Type.Nil => null,
Type.Max or _ =>
throw new InvalidOperationException($"Invalid Variant type: {NativeVar.DangerousSelfRef.Type}"),
};
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Variant From<[MustBeVariant] T>(in T from) =>