Merge pull request #68310 from neikeq/csharp-opt-variant-generic-conv
C#: Optimize Variant conversion callbacks
This commit is contained in:
commit
fcdded2e3d
|
@ -2274,7 +2274,7 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
|
|||
p_output.append(");\n");
|
||||
|
||||
// Generate Callable trampoline for the delegate
|
||||
p_output << MEMBER_BEGIN "private static unsafe void " << p_isignal.proxy_name << "Trampoline"
|
||||
p_output << MEMBER_BEGIN "private static void " << p_isignal.proxy_name << "Trampoline"
|
||||
<< "(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)\n"
|
||||
<< INDENT1 "{\n"
|
||||
<< INDENT2 "Callable.ThrowIfArgCountMismatch(args, " << itos(p_isignal.arguments.size()) << ");\n"
|
||||
|
@ -2289,9 +2289,8 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
|
|||
p_output << ",";
|
||||
}
|
||||
|
||||
// TODO: We don't need to use VariantConversionCallbacks. We have the type information so we can use [cs_variant_to_managed] and [cs_managed_to_variant].
|
||||
p_output << "\n" INDENT3 "VariantConversionCallbacks.GetToManagedCallback<"
|
||||
<< arg_type->cs_type << ">()(args[" << itos(idx) << "])";
|
||||
p_output << sformat(arg_type->cs_variant_to_managed,
|
||||
"args[" + itos(idx) + "]", arg_type->cs_type, arg_type->name);
|
||||
|
||||
idx++;
|
||||
}
|
||||
|
|
|
@ -495,35 +495,10 @@ namespace Godot.Collections
|
|||
private static Array<T> FromVariantFunc(in godot_variant variant) =>
|
||||
VariantUtils.ConvertToArrayObject<T>(variant);
|
||||
|
||||
// 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 unsafe delegate* managed<in T, godot_variant> ConvertToVariantCallback;
|
||||
private static readonly unsafe delegate* managed<in godot_variant, T> ConvertToManagedCallback;
|
||||
|
||||
// ReSharper restore StaticMemberInGenericType
|
||||
|
||||
static unsafe Array()
|
||||
{
|
||||
VariantConversionCallbacks.GenericConversionCallbacks[typeof(Array<T>)] =
|
||||
(
|
||||
(IntPtr)(delegate* managed<in Array<T>, godot_variant>)&ToVariantFunc,
|
||||
(IntPtr)(delegate* managed<in godot_variant, Array<T>>)&FromVariantFunc
|
||||
);
|
||||
|
||||
ConvertToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<T>();
|
||||
ConvertToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<T>();
|
||||
}
|
||||
|
||||
private static unsafe void ValidateVariantConversionCallbacks()
|
||||
{
|
||||
if (ConvertToVariantCallback == null || ConvertToManagedCallback == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"The array element type is not supported for conversion to Variant: '{typeof(T).FullName}'.");
|
||||
}
|
||||
VariantUtils.GenericConversion<Array<T>>.ToVariantCb = &ToVariantFunc;
|
||||
VariantUtils.GenericConversion<Array<T>>.FromVariantCb = &FromVariantFunc;
|
||||
}
|
||||
|
||||
private readonly Array _underlyingArray;
|
||||
|
@ -539,8 +514,6 @@ namespace Godot.Collections
|
|||
/// </summary>
|
||||
public Array()
|
||||
{
|
||||
ValidateVariantConversionCallbacks();
|
||||
|
||||
_underlyingArray = new Array();
|
||||
}
|
||||
|
||||
|
@ -551,8 +524,6 @@ namespace Godot.Collections
|
|||
/// <returns>A new Godot Array.</returns>
|
||||
public Array(IEnumerable<T> collection)
|
||||
{
|
||||
ValidateVariantConversionCallbacks();
|
||||
|
||||
if (collection == null)
|
||||
throw new ArgumentNullException(nameof(collection));
|
||||
|
||||
|
@ -569,8 +540,6 @@ namespace Godot.Collections
|
|||
/// <returns>A new Godot Array.</returns>
|
||||
public Array(T[] array) : this()
|
||||
{
|
||||
ValidateVariantConversionCallbacks();
|
||||
|
||||
if (array == null)
|
||||
throw new ArgumentNullException(nameof(array));
|
||||
|
||||
|
@ -586,8 +555,6 @@ namespace Godot.Collections
|
|||
/// <param name="array">The untyped array to construct from.</param>
|
||||
public Array(Array array)
|
||||
{
|
||||
ValidateVariantConversionCallbacks();
|
||||
|
||||
_underlyingArray = array;
|
||||
}
|
||||
|
||||
|
@ -665,7 +632,7 @@ namespace Godot.Collections
|
|||
get
|
||||
{
|
||||
_underlyingArray.GetVariantBorrowElementAt(index, out godot_variant borrowElem);
|
||||
return ConvertToManagedCallback(borrowElem);
|
||||
return VariantUtils.ConvertTo<T>(borrowElem);
|
||||
}
|
||||
set
|
||||
{
|
||||
|
@ -675,7 +642,7 @@ namespace Godot.Collections
|
|||
godot_variant* ptrw = NativeFuncs.godotsharp_array_ptrw(ref self);
|
||||
godot_variant* itemPtr = &ptrw[index];
|
||||
(*itemPtr).Dispose();
|
||||
*itemPtr = ConvertToVariantCallback(value);
|
||||
*itemPtr = VariantUtils.CreateFrom(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -685,9 +652,9 @@ namespace Godot.Collections
|
|||
/// </summary>
|
||||
/// <param name="item">The item to search for.</param>
|
||||
/// <returns>The index of the item, or -1 if not found.</returns>
|
||||
public unsafe int IndexOf(T item)
|
||||
public int IndexOf(T item)
|
||||
{
|
||||
using var variantValue = ConvertToVariantCallback(item);
|
||||
using var variantValue = VariantUtils.CreateFrom(item);
|
||||
var self = (godot_array)_underlyingArray.NativeValue;
|
||||
return NativeFuncs.godotsharp_array_index_of(ref self, variantValue);
|
||||
}
|
||||
|
@ -700,12 +667,12 @@ namespace Godot.Collections
|
|||
/// </summary>
|
||||
/// <param name="index">The index to insert at.</param>
|
||||
/// <param name="item">The item to insert.</param>
|
||||
public unsafe void Insert(int index, T item)
|
||||
public void Insert(int index, T item)
|
||||
{
|
||||
if (index < 0 || index > Count)
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
|
||||
using var variantValue = ConvertToVariantCallback(item);
|
||||
using var variantValue = VariantUtils.CreateFrom(item);
|
||||
var self = (godot_array)_underlyingArray.NativeValue;
|
||||
NativeFuncs.godotsharp_array_insert(ref self, index, variantValue);
|
||||
}
|
||||
|
@ -736,9 +703,9 @@ namespace Godot.Collections
|
|||
/// </summary>
|
||||
/// <param name="item">The item to add.</param>
|
||||
/// <returns>The new size after adding the item.</returns>
|
||||
public unsafe void Add(T item)
|
||||
public void Add(T item)
|
||||
{
|
||||
using var variantValue = ConvertToVariantCallback(item);
|
||||
using var variantValue = VariantUtils.CreateFrom(item);
|
||||
var self = (godot_array)_underlyingArray.NativeValue;
|
||||
_ = NativeFuncs.godotsharp_array_add(ref self, variantValue);
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ public readonly partial struct Callable
|
|||
ThrowIfArgCountMismatch(args, 1);
|
||||
|
||||
((Action<T0>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0])
|
||||
VariantUtils.ConvertTo<T0>(args[0])
|
||||
);
|
||||
|
||||
ret = default;
|
||||
|
@ -73,8 +73,8 @@ public readonly partial struct Callable
|
|||
ThrowIfArgCountMismatch(args, 2);
|
||||
|
||||
((Action<T0, T1>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1])
|
||||
VariantUtils.ConvertTo<T0>(args[0]),
|
||||
VariantUtils.ConvertTo<T1>(args[1])
|
||||
);
|
||||
|
||||
ret = default;
|
||||
|
@ -93,9 +93,9 @@ public readonly partial struct Callable
|
|||
ThrowIfArgCountMismatch(args, 3);
|
||||
|
||||
((Action<T0, T1, T2>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2])
|
||||
VariantUtils.ConvertTo<T0>(args[0]),
|
||||
VariantUtils.ConvertTo<T1>(args[1]),
|
||||
VariantUtils.ConvertTo<T2>(args[2])
|
||||
);
|
||||
|
||||
ret = default;
|
||||
|
@ -114,10 +114,10 @@ public readonly partial struct Callable
|
|||
ThrowIfArgCountMismatch(args, 4);
|
||||
|
||||
((Action<T0, T1, T2, T3>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3])
|
||||
VariantUtils.ConvertTo<T0>(args[0]),
|
||||
VariantUtils.ConvertTo<T1>(args[1]),
|
||||
VariantUtils.ConvertTo<T2>(args[2]),
|
||||
VariantUtils.ConvertTo<T3>(args[3])
|
||||
);
|
||||
|
||||
ret = default;
|
||||
|
@ -136,11 +136,11 @@ public readonly partial struct Callable
|
|||
ThrowIfArgCountMismatch(args, 5);
|
||||
|
||||
((Action<T0, T1, T2, T3, T4>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4])
|
||||
VariantUtils.ConvertTo<T0>(args[0]),
|
||||
VariantUtils.ConvertTo<T1>(args[1]),
|
||||
VariantUtils.ConvertTo<T2>(args[2]),
|
||||
VariantUtils.ConvertTo<T3>(args[3]),
|
||||
VariantUtils.ConvertTo<T4>(args[4])
|
||||
);
|
||||
|
||||
ret = default;
|
||||
|
@ -159,12 +159,12 @@ public readonly partial struct Callable
|
|||
ThrowIfArgCountMismatch(args, 6);
|
||||
|
||||
((Action<T0, T1, T2, T3, T4, T5>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5])
|
||||
VariantUtils.ConvertTo<T0>(args[0]),
|
||||
VariantUtils.ConvertTo<T1>(args[1]),
|
||||
VariantUtils.ConvertTo<T2>(args[2]),
|
||||
VariantUtils.ConvertTo<T3>(args[3]),
|
||||
VariantUtils.ConvertTo<T4>(args[4]),
|
||||
VariantUtils.ConvertTo<T5>(args[5])
|
||||
);
|
||||
|
||||
ret = default;
|
||||
|
@ -183,13 +183,13 @@ public readonly partial struct Callable
|
|||
ThrowIfArgCountMismatch(args, 7);
|
||||
|
||||
((Action<T0, T1, T2, T3, T4, T5, T6>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6])
|
||||
VariantUtils.ConvertTo<T0>(args[0]),
|
||||
VariantUtils.ConvertTo<T1>(args[1]),
|
||||
VariantUtils.ConvertTo<T2>(args[2]),
|
||||
VariantUtils.ConvertTo<T3>(args[3]),
|
||||
VariantUtils.ConvertTo<T4>(args[4]),
|
||||
VariantUtils.ConvertTo<T5>(args[5]),
|
||||
VariantUtils.ConvertTo<T6>(args[6])
|
||||
);
|
||||
|
||||
ret = default;
|
||||
|
@ -208,14 +208,14 @@ public readonly partial struct Callable
|
|||
ThrowIfArgCountMismatch(args, 8);
|
||||
|
||||
((Action<T0, T1, T2, T3, T4, T5, T6, T7>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T7>()(args[7])
|
||||
VariantUtils.ConvertTo<T0>(args[0]),
|
||||
VariantUtils.ConvertTo<T1>(args[1]),
|
||||
VariantUtils.ConvertTo<T2>(args[2]),
|
||||
VariantUtils.ConvertTo<T3>(args[3]),
|
||||
VariantUtils.ConvertTo<T4>(args[4]),
|
||||
VariantUtils.ConvertTo<T5>(args[5]),
|
||||
VariantUtils.ConvertTo<T6>(args[6]),
|
||||
VariantUtils.ConvertTo<T7>(args[7])
|
||||
);
|
||||
|
||||
ret = default;
|
||||
|
@ -234,15 +234,15 @@ public readonly partial struct Callable
|
|||
ThrowIfArgCountMismatch(args, 9);
|
||||
|
||||
((Action<T0, T1, T2, T3, T4, T5, T6, T7, T8>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T7>()(args[7]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T8>()(args[8])
|
||||
VariantUtils.ConvertTo<T0>(args[0]),
|
||||
VariantUtils.ConvertTo<T1>(args[1]),
|
||||
VariantUtils.ConvertTo<T2>(args[2]),
|
||||
VariantUtils.ConvertTo<T3>(args[3]),
|
||||
VariantUtils.ConvertTo<T4>(args[4]),
|
||||
VariantUtils.ConvertTo<T5>(args[5]),
|
||||
VariantUtils.ConvertTo<T6>(args[6]),
|
||||
VariantUtils.ConvertTo<T7>(args[7]),
|
||||
VariantUtils.ConvertTo<T8>(args[8])
|
||||
);
|
||||
|
||||
ret = default;
|
||||
|
@ -265,7 +265,7 @@ public readonly partial struct Callable
|
|||
|
||||
TResult res = ((Func<TResult>)delegateObj)();
|
||||
|
||||
ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
|
||||
ret = VariantUtils.CreateFrom(res);
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(func, &Trampoline);
|
||||
|
@ -281,10 +281,10 @@ public readonly partial struct Callable
|
|||
ThrowIfArgCountMismatch(args, 1);
|
||||
|
||||
TResult res = ((Func<T0, TResult>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0])
|
||||
VariantUtils.ConvertTo<T0>(args[0])
|
||||
);
|
||||
|
||||
ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
|
||||
ret = VariantUtils.CreateFrom(res);
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(func, &Trampoline);
|
||||
|
@ -300,11 +300,11 @@ public readonly partial struct Callable
|
|||
ThrowIfArgCountMismatch(args, 2);
|
||||
|
||||
TResult res = ((Func<T0, T1, TResult>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1])
|
||||
VariantUtils.ConvertTo<T0>(args[0]),
|
||||
VariantUtils.ConvertTo<T1>(args[1])
|
||||
);
|
||||
|
||||
ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
|
||||
ret = VariantUtils.CreateFrom(res);
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(func, &Trampoline);
|
||||
|
@ -320,12 +320,12 @@ public readonly partial struct Callable
|
|||
ThrowIfArgCountMismatch(args, 3);
|
||||
|
||||
TResult res = ((Func<T0, T1, T2, TResult>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2])
|
||||
VariantUtils.ConvertTo<T0>(args[0]),
|
||||
VariantUtils.ConvertTo<T1>(args[1]),
|
||||
VariantUtils.ConvertTo<T2>(args[2])
|
||||
);
|
||||
|
||||
ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
|
||||
ret = VariantUtils.CreateFrom(res);
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(func, &Trampoline);
|
||||
|
@ -341,13 +341,13 @@ public readonly partial struct Callable
|
|||
ThrowIfArgCountMismatch(args, 4);
|
||||
|
||||
TResult res = ((Func<T0, T1, T2, T3, TResult>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3])
|
||||
VariantUtils.ConvertTo<T0>(args[0]),
|
||||
VariantUtils.ConvertTo<T1>(args[1]),
|
||||
VariantUtils.ConvertTo<T2>(args[2]),
|
||||
VariantUtils.ConvertTo<T3>(args[3])
|
||||
);
|
||||
|
||||
ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
|
||||
ret = VariantUtils.CreateFrom(res);
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(func, &Trampoline);
|
||||
|
@ -363,14 +363,14 @@ public readonly partial struct Callable
|
|||
ThrowIfArgCountMismatch(args, 5);
|
||||
|
||||
TResult res = ((Func<T0, T1, T2, T3, T4, TResult>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4])
|
||||
VariantUtils.ConvertTo<T0>(args[0]),
|
||||
VariantUtils.ConvertTo<T1>(args[1]),
|
||||
VariantUtils.ConvertTo<T2>(args[2]),
|
||||
VariantUtils.ConvertTo<T3>(args[3]),
|
||||
VariantUtils.ConvertTo<T4>(args[4])
|
||||
);
|
||||
|
||||
ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
|
||||
ret = VariantUtils.CreateFrom(res);
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(func, &Trampoline);
|
||||
|
@ -386,15 +386,15 @@ public readonly partial struct Callable
|
|||
ThrowIfArgCountMismatch(args, 6);
|
||||
|
||||
TResult res = ((Func<T0, T1, T2, T3, T4, T5, TResult>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5])
|
||||
VariantUtils.ConvertTo<T0>(args[0]),
|
||||
VariantUtils.ConvertTo<T1>(args[1]),
|
||||
VariantUtils.ConvertTo<T2>(args[2]),
|
||||
VariantUtils.ConvertTo<T3>(args[3]),
|
||||
VariantUtils.ConvertTo<T4>(args[4]),
|
||||
VariantUtils.ConvertTo<T5>(args[5])
|
||||
);
|
||||
|
||||
ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
|
||||
ret = VariantUtils.CreateFrom(res);
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(func, &Trampoline);
|
||||
|
@ -410,16 +410,16 @@ public readonly partial struct Callable
|
|||
ThrowIfArgCountMismatch(args, 7);
|
||||
|
||||
TResult res = ((Func<T0, T1, T2, T3, T4, T5, T6, TResult>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6])
|
||||
VariantUtils.ConvertTo<T0>(args[0]),
|
||||
VariantUtils.ConvertTo<T1>(args[1]),
|
||||
VariantUtils.ConvertTo<T2>(args[2]),
|
||||
VariantUtils.ConvertTo<T3>(args[3]),
|
||||
VariantUtils.ConvertTo<T4>(args[4]),
|
||||
VariantUtils.ConvertTo<T5>(args[5]),
|
||||
VariantUtils.ConvertTo<T6>(args[6])
|
||||
);
|
||||
|
||||
ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
|
||||
ret = VariantUtils.CreateFrom(res);
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(func, &Trampoline);
|
||||
|
@ -435,17 +435,17 @@ public readonly partial struct Callable
|
|||
ThrowIfArgCountMismatch(args, 8);
|
||||
|
||||
TResult res = ((Func<T0, T1, T2, T3, T4, T5, T6, T7, TResult>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T7>()(args[7])
|
||||
VariantUtils.ConvertTo<T0>(args[0]),
|
||||
VariantUtils.ConvertTo<T1>(args[1]),
|
||||
VariantUtils.ConvertTo<T2>(args[2]),
|
||||
VariantUtils.ConvertTo<T3>(args[3]),
|
||||
VariantUtils.ConvertTo<T4>(args[4]),
|
||||
VariantUtils.ConvertTo<T5>(args[5]),
|
||||
VariantUtils.ConvertTo<T6>(args[6]),
|
||||
VariantUtils.ConvertTo<T7>(args[7])
|
||||
);
|
||||
|
||||
ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
|
||||
ret = VariantUtils.CreateFrom(res);
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(func, &Trampoline);
|
||||
|
@ -461,18 +461,18 @@ public readonly partial struct Callable
|
|||
ThrowIfArgCountMismatch(args, 9);
|
||||
|
||||
TResult res = ((Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, TResult>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T7>()(args[7]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T8>()(args[8])
|
||||
VariantUtils.ConvertTo<T0>(args[0]),
|
||||
VariantUtils.ConvertTo<T1>(args[1]),
|
||||
VariantUtils.ConvertTo<T2>(args[2]),
|
||||
VariantUtils.ConvertTo<T3>(args[3]),
|
||||
VariantUtils.ConvertTo<T4>(args[4]),
|
||||
VariantUtils.ConvertTo<T5>(args[5]),
|
||||
VariantUtils.ConvertTo<T6>(args[6]),
|
||||
VariantUtils.ConvertTo<T7>(args[7]),
|
||||
VariantUtils.ConvertTo<T8>(args[8])
|
||||
);
|
||||
|
||||
ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
|
||||
ret = VariantUtils.CreateFrom(res);
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(func, &Trampoline);
|
||||
|
|
|
@ -362,45 +362,10 @@ namespace Godot.Collections
|
|||
private static Dictionary<TKey, TValue> FromVariantFunc(in godot_variant variant) =>
|
||||
VariantUtils.ConvertToDictionaryObject<TKey, TValue>(variant);
|
||||
|
||||
// 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 unsafe delegate* managed<in TKey, godot_variant> ConvertKeyToVariantCallback;
|
||||
private static readonly unsafe delegate* managed<in godot_variant, TKey> ConvertKeyToManagedCallback;
|
||||
private static readonly unsafe delegate* managed<in TValue, godot_variant> ConvertValueToVariantCallback;
|
||||
private static readonly unsafe delegate* managed<in godot_variant, TValue> ConvertValueToManagedCallback;
|
||||
|
||||
// ReSharper restore StaticMemberInGenericType
|
||||
|
||||
static unsafe Dictionary()
|
||||
{
|
||||
VariantConversionCallbacks.GenericConversionCallbacks[typeof(Dictionary<TKey, TValue>)] =
|
||||
(
|
||||
(IntPtr)(delegate* managed<in Dictionary<TKey, TValue>, godot_variant>)&ToVariantFunc,
|
||||
(IntPtr)(delegate* managed<in godot_variant, Dictionary<TKey, TValue>>)&FromVariantFunc
|
||||
);
|
||||
|
||||
ConvertKeyToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<TKey>();
|
||||
ConvertKeyToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<TKey>();
|
||||
ConvertValueToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<TValue>();
|
||||
ConvertValueToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<TValue>();
|
||||
}
|
||||
|
||||
private static unsafe void ValidateVariantConversionCallbacks()
|
||||
{
|
||||
if (ConvertKeyToVariantCallback == null || ConvertKeyToManagedCallback == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"The dictionary key type is not supported for conversion to Variant: '{typeof(TKey).FullName}'.");
|
||||
}
|
||||
|
||||
if (ConvertValueToVariantCallback == null || ConvertValueToManagedCallback == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"The dictionary value type is not supported for conversion to Variant: '{typeof(TValue).FullName}'.");
|
||||
}
|
||||
VariantUtils.GenericConversion<Dictionary<TKey, TValue>>.ToVariantCb = &ToVariantFunc;
|
||||
VariantUtils.GenericConversion<Dictionary<TKey, TValue>>.FromVariantCb = &FromVariantFunc;
|
||||
}
|
||||
|
||||
private readonly Dictionary _underlyingDict;
|
||||
|
@ -416,8 +381,6 @@ namespace Godot.Collections
|
|||
/// </summary>
|
||||
public Dictionary()
|
||||
{
|
||||
ValidateVariantConversionCallbacks();
|
||||
|
||||
_underlyingDict = new Dictionary();
|
||||
}
|
||||
|
||||
|
@ -428,8 +391,6 @@ namespace Godot.Collections
|
|||
/// <returns>A new Godot Dictionary.</returns>
|
||||
public Dictionary(IDictionary<TKey, TValue> dictionary)
|
||||
{
|
||||
ValidateVariantConversionCallbacks();
|
||||
|
||||
if (dictionary == null)
|
||||
throw new ArgumentNullException(nameof(dictionary));
|
||||
|
||||
|
@ -446,8 +407,6 @@ namespace Godot.Collections
|
|||
/// <returns>A new Godot Dictionary.</returns>
|
||||
public Dictionary(Dictionary dictionary)
|
||||
{
|
||||
ValidateVariantConversionCallbacks();
|
||||
|
||||
_underlyingDict = dictionary;
|
||||
}
|
||||
|
||||
|
@ -481,18 +440,18 @@ namespace Godot.Collections
|
|||
/// Returns the value at the given <paramref name="key"/>.
|
||||
/// </summary>
|
||||
/// <value>The value at the given <paramref name="key"/>.</value>
|
||||
public unsafe TValue this[TKey key]
|
||||
public TValue this[TKey key]
|
||||
{
|
||||
get
|
||||
{
|
||||
using var variantKey = ConvertKeyToVariantCallback(key);
|
||||
using var variantKey = VariantUtils.CreateFrom(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 ConvertValueToManagedCallback(value);
|
||||
return VariantUtils.ConvertTo<TValue>(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -501,8 +460,8 @@ namespace Godot.Collections
|
|||
}
|
||||
set
|
||||
{
|
||||
using var variantKey = ConvertKeyToVariantCallback(key);
|
||||
using var variantValue = ConvertValueToVariantCallback(value);
|
||||
using var variantKey = VariantUtils.CreateFrom(key);
|
||||
using var variantValue = VariantUtils.CreateFrom(value);
|
||||
var self = (godot_dictionary)_underlyingDict.NativeValue;
|
||||
NativeFuncs.godotsharp_dictionary_set_value(ref self,
|
||||
variantKey, variantValue);
|
||||
|
@ -541,7 +500,7 @@ namespace Godot.Collections
|
|||
|
||||
IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => Values;
|
||||
|
||||
private unsafe KeyValuePair<TKey, TValue> GetKeyValuePair(int index)
|
||||
private KeyValuePair<TKey, TValue> GetKeyValuePair(int index)
|
||||
{
|
||||
var self = (godot_dictionary)_underlyingDict.NativeValue;
|
||||
NativeFuncs.godotsharp_dictionary_key_value_pair_at(ref self, index,
|
||||
|
@ -551,8 +510,8 @@ namespace Godot.Collections
|
|||
using (value)
|
||||
{
|
||||
return new KeyValuePair<TKey, TValue>(
|
||||
ConvertKeyToManagedCallback(key),
|
||||
ConvertValueToManagedCallback(value));
|
||||
VariantUtils.ConvertTo<TKey>(key),
|
||||
VariantUtils.ConvertTo<TValue>(value));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -562,15 +521,15 @@ namespace Godot.Collections
|
|||
/// </summary>
|
||||
/// <param name="key">The key at which to add the object.</param>
|
||||
/// <param name="value">The object to add.</param>
|
||||
public unsafe void Add(TKey key, TValue value)
|
||||
public void Add(TKey key, TValue value)
|
||||
{
|
||||
using var variantKey = ConvertKeyToVariantCallback(key);
|
||||
using var variantKey = VariantUtils.CreateFrom(key);
|
||||
var self = (godot_dictionary)_underlyingDict.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 var variantValue = ConvertValueToVariantCallback(value);
|
||||
using var variantValue = VariantUtils.CreateFrom(value);
|
||||
NativeFuncs.godotsharp_dictionary_add(ref self, variantKey, variantValue);
|
||||
}
|
||||
|
||||
|
@ -579,9 +538,9 @@ namespace Godot.Collections
|
|||
/// </summary>
|
||||
/// <param name="key">The key to look for.</param>
|
||||
/// <returns>Whether or not this dictionary contains the given key.</returns>
|
||||
public unsafe bool ContainsKey(TKey key)
|
||||
public bool ContainsKey(TKey key)
|
||||
{
|
||||
using var variantKey = ConvertKeyToVariantCallback(key);
|
||||
using var variantKey = VariantUtils.CreateFrom(key);
|
||||
var self = (godot_dictionary)_underlyingDict.NativeValue;
|
||||
return NativeFuncs.godotsharp_dictionary_contains_key(ref self, variantKey).ToBool();
|
||||
}
|
||||
|
@ -590,9 +549,9 @@ namespace Godot.Collections
|
|||
/// Removes an element from this <see cref="Dictionary{TKey, TValue}"/> by key.
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the element to remove.</param>
|
||||
public unsafe bool Remove(TKey key)
|
||||
public bool Remove(TKey key)
|
||||
{
|
||||
using var variantKey = ConvertKeyToVariantCallback(key);
|
||||
using var variantKey = VariantUtils.CreateFrom(key);
|
||||
var self = (godot_dictionary)_underlyingDict.NativeValue;
|
||||
return NativeFuncs.godotsharp_dictionary_remove_key(ref self, variantKey).ToBool();
|
||||
}
|
||||
|
@ -603,15 +562,15 @@ namespace Godot.Collections
|
|||
/// <param name="key">The key of the element to get.</param>
|
||||
/// <param name="value">The value at the given <paramref name="key"/>.</param>
|
||||
/// <returns>If an object was found for the given <paramref name="key"/>.</returns>
|
||||
public unsafe bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
|
||||
public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
|
||||
{
|
||||
using var variantKey = ConvertKeyToVariantCallback(key);
|
||||
using var variantKey = VariantUtils.CreateFrom(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 ? ConvertValueToManagedCallback(retValue) : default;
|
||||
value = found ? VariantUtils.ConvertTo<TValue>(retValue) : default;
|
||||
|
||||
return found;
|
||||
}
|
||||
|
@ -635,9 +594,9 @@ namespace Godot.Collections
|
|||
/// </summary>
|
||||
public void Clear() => _underlyingDict.Clear();
|
||||
|
||||
unsafe bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
using var variantKey = ConvertKeyToVariantCallback(item.Key);
|
||||
using var variantKey = VariantUtils.CreateFrom(item.Key);
|
||||
var self = (godot_dictionary)_underlyingDict.NativeValue;
|
||||
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
|
||||
variantKey, out godot_variant retValue).ToBool();
|
||||
|
@ -647,7 +606,7 @@ namespace Godot.Collections
|
|||
if (!found)
|
||||
return false;
|
||||
|
||||
using var variantValue = ConvertValueToVariantCallback(item.Value);
|
||||
using var variantValue = VariantUtils.CreateFrom(item.Value);
|
||||
return NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool();
|
||||
}
|
||||
}
|
||||
|
@ -680,9 +639,9 @@ namespace Godot.Collections
|
|||
}
|
||||
}
|
||||
|
||||
unsafe bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
using var variantKey = ConvertKeyToVariantCallback(item.Key);
|
||||
using var variantKey = VariantUtils.CreateFrom(item.Key);
|
||||
var self = (godot_dictionary)_underlyingDict.NativeValue;
|
||||
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
|
||||
variantKey, out godot_variant retValue).ToBool();
|
||||
|
@ -692,7 +651,7 @@ namespace Godot.Collections
|
|||
if (!found)
|
||||
return false;
|
||||
|
||||
using var variantValue = ConvertValueToVariantCallback(item.Value);
|
||||
using var variantValue = VariantUtils.CreateFrom(item.Value);
|
||||
if (NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool())
|
||||
{
|
||||
return NativeFuncs.godotsharp_dictionary_remove_key(
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -8,7 +8,7 @@ using Godot.Collections;
|
|||
|
||||
namespace Godot.NativeInterop
|
||||
{
|
||||
public static class VariantUtils
|
||||
public static partial class VariantUtils
|
||||
{
|
||||
public static godot_variant CreateFromRID(RID from)
|
||||
=> new() { Type = Variant.Type.Rid, RID = from };
|
||||
|
|
|
@ -0,0 +1,406 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Godot.NativeInterop;
|
||||
|
||||
public partial class VariantUtils
|
||||
{
|
||||
private static Exception UnsupportedType<T>() => throw new InvalidOperationException(
|
||||
$"The type is not supported for conversion to/from Variant: '{typeof(T).FullName}'");
|
||||
|
||||
internal static class GenericConversion<T>
|
||||
{
|
||||
public static unsafe godot_variant ToVariant(in T from) =>
|
||||
ToVariantCb != null ? ToVariantCb(from) : throw UnsupportedType<T>();
|
||||
|
||||
public static unsafe T FromVariant(in godot_variant variant) =>
|
||||
FromVariantCb != null ? FromVariantCb(variant) : throw UnsupportedType<T>();
|
||||
|
||||
// ReSharper disable once StaticMemberInGenericType
|
||||
internal static unsafe delegate*<in T, godot_variant> ToVariantCb;
|
||||
|
||||
// ReSharper disable once StaticMemberInGenericType
|
||||
internal static unsafe delegate*<in godot_variant, T> FromVariantCb;
|
||||
|
||||
[SuppressMessage("ReSharper", "RedundantNameQualifier")]
|
||||
static GenericConversion()
|
||||
{
|
||||
RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
[SuppressMessage("ReSharper", "RedundantNameQualifier")]
|
||||
public static godot_variant CreateFrom<[MustBeVariant] T>(in T from)
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
static TTo UnsafeAs<TTo>(in T f) => Unsafe.As<T, TTo>(ref Unsafe.AsRef(f));
|
||||
|
||||
// `typeof(T) == typeof(X)` is optimized away. We cannot cache `typeof(T)` in a local variable, as it's not optimized when done like that.
|
||||
|
||||
if (typeof(T) == typeof(bool))
|
||||
return CreateFromBool(UnsafeAs<bool>(from));
|
||||
|
||||
if (typeof(T) == typeof(char))
|
||||
return CreateFromInt(UnsafeAs<char>(from));
|
||||
|
||||
if (typeof(T) == typeof(sbyte))
|
||||
return CreateFromInt(UnsafeAs<sbyte>(from));
|
||||
|
||||
if (typeof(T) == typeof(short))
|
||||
return CreateFromInt(UnsafeAs<short>(from));
|
||||
|
||||
if (typeof(T) == typeof(int))
|
||||
return CreateFromInt(UnsafeAs<int>(from));
|
||||
|
||||
if (typeof(T) == typeof(long))
|
||||
return CreateFromInt(UnsafeAs<long>(from));
|
||||
|
||||
if (typeof(T) == typeof(byte))
|
||||
return CreateFromInt(UnsafeAs<byte>(from));
|
||||
|
||||
if (typeof(T) == typeof(ushort))
|
||||
return CreateFromInt(UnsafeAs<ushort>(from));
|
||||
|
||||
if (typeof(T) == typeof(uint))
|
||||
return CreateFromInt(UnsafeAs<uint>(from));
|
||||
|
||||
if (typeof(T) == typeof(ulong))
|
||||
return CreateFromInt(UnsafeAs<ulong>(from));
|
||||
|
||||
if (typeof(T) == typeof(float))
|
||||
return CreateFromFloat(UnsafeAs<float>(from));
|
||||
|
||||
if (typeof(T) == typeof(double))
|
||||
return CreateFromFloat(UnsafeAs<double>(from));
|
||||
|
||||
if (typeof(T) == typeof(Vector2))
|
||||
return CreateFromVector2(UnsafeAs<Vector2>(from));
|
||||
|
||||
if (typeof(T) == typeof(Vector2i))
|
||||
return CreateFromVector2i(UnsafeAs<Vector2i>(from));
|
||||
|
||||
if (typeof(T) == typeof(Rect2))
|
||||
return CreateFromRect2(UnsafeAs<Rect2>(from));
|
||||
|
||||
if (typeof(T) == typeof(Rect2i))
|
||||
return CreateFromRect2i(UnsafeAs<Rect2i>(from));
|
||||
|
||||
if (typeof(T) == typeof(Transform2D))
|
||||
return CreateFromTransform2D(UnsafeAs<Transform2D>(from));
|
||||
|
||||
if (typeof(T) == typeof(Vector3))
|
||||
return CreateFromVector3(UnsafeAs<Vector3>(from));
|
||||
|
||||
if (typeof(T) == typeof(Vector3i))
|
||||
return CreateFromVector3i(UnsafeAs<Vector3i>(from));
|
||||
|
||||
if (typeof(T) == typeof(Basis))
|
||||
return CreateFromBasis(UnsafeAs<Basis>(from));
|
||||
|
||||
if (typeof(T) == typeof(Quaternion))
|
||||
return CreateFromQuaternion(UnsafeAs<Quaternion>(from));
|
||||
|
||||
if (typeof(T) == typeof(Transform3D))
|
||||
return CreateFromTransform3D(UnsafeAs<Transform3D>(from));
|
||||
|
||||
if (typeof(T) == typeof(Vector4))
|
||||
return CreateFromVector4(UnsafeAs<Vector4>(from));
|
||||
|
||||
if (typeof(T) == typeof(Vector4i))
|
||||
return CreateFromVector4i(UnsafeAs<Vector4i>(from));
|
||||
|
||||
if (typeof(T) == typeof(AABB))
|
||||
return CreateFromAABB(UnsafeAs<AABB>(from));
|
||||
|
||||
if (typeof(T) == typeof(Color))
|
||||
return CreateFromColor(UnsafeAs<Color>(from));
|
||||
|
||||
if (typeof(T) == typeof(Plane))
|
||||
return CreateFromPlane(UnsafeAs<Plane>(from));
|
||||
|
||||
if (typeof(T) == typeof(Callable))
|
||||
return CreateFromCallable(UnsafeAs<Callable>(from));
|
||||
|
||||
if (typeof(T) == typeof(SignalInfo))
|
||||
return CreateFromSignalInfo(UnsafeAs<SignalInfo>(from));
|
||||
|
||||
if (typeof(T) == typeof(string))
|
||||
return CreateFromString(UnsafeAs<string>(from));
|
||||
|
||||
if (typeof(T) == typeof(byte[]))
|
||||
return CreateFromPackedByteArray(UnsafeAs<byte[]>(from));
|
||||
|
||||
if (typeof(T) == typeof(int[]))
|
||||
return CreateFromPackedInt32Array(UnsafeAs<int[]>(from));
|
||||
|
||||
if (typeof(T) == typeof(long[]))
|
||||
return CreateFromPackedInt64Array(UnsafeAs<long[]>(from));
|
||||
|
||||
if (typeof(T) == typeof(float[]))
|
||||
return CreateFromPackedFloat32Array(UnsafeAs<float[]>(from));
|
||||
|
||||
if (typeof(T) == typeof(double[]))
|
||||
return CreateFromPackedFloat64Array(UnsafeAs<double[]>(from));
|
||||
|
||||
if (typeof(T) == typeof(string[]))
|
||||
return CreateFromPackedStringArray(UnsafeAs<string[]>(from));
|
||||
|
||||
if (typeof(T) == typeof(Vector2[]))
|
||||
return CreateFromPackedVector2Array(UnsafeAs<Vector2[]>(from));
|
||||
|
||||
if (typeof(T) == typeof(Vector3[]))
|
||||
return CreateFromPackedVector3Array(UnsafeAs<Vector3[]>(from));
|
||||
|
||||
if (typeof(T) == typeof(Color[]))
|
||||
return CreateFromPackedColorArray(UnsafeAs<Color[]>(from));
|
||||
|
||||
if (typeof(T) == typeof(StringName[]))
|
||||
return CreateFromSystemArrayOfStringName(UnsafeAs<StringName[]>(from));
|
||||
|
||||
if (typeof(T) == typeof(NodePath[]))
|
||||
return CreateFromSystemArrayOfNodePath(UnsafeAs<NodePath[]>(from));
|
||||
|
||||
if (typeof(T) == typeof(RID[]))
|
||||
return CreateFromSystemArrayOfRID(UnsafeAs<RID[]>(from));
|
||||
|
||||
if (typeof(T) == typeof(StringName))
|
||||
return CreateFromStringName(UnsafeAs<StringName>(from));
|
||||
|
||||
if (typeof(T) == typeof(NodePath))
|
||||
return CreateFromNodePath(UnsafeAs<NodePath>(from));
|
||||
|
||||
if (typeof(T) == typeof(RID))
|
||||
return CreateFromRID(UnsafeAs<RID>(from));
|
||||
|
||||
if (typeof(T) == typeof(Godot.Collections.Dictionary))
|
||||
return CreateFromDictionary(UnsafeAs<Godot.Collections.Dictionary>(from));
|
||||
|
||||
if (typeof(T) == typeof(Godot.Collections.Array))
|
||||
return CreateFromArray(UnsafeAs<Godot.Collections.Array>(from));
|
||||
|
||||
if (typeof(T) == typeof(Variant))
|
||||
return NativeFuncs.godotsharp_variant_new_copy((godot_variant)UnsafeAs<Variant>(from).NativeVar);
|
||||
|
||||
// More complex checks here at the end, to avoid screwing the simple ones in case they're not optimized away.
|
||||
|
||||
// `typeof(X).IsAssignableFrom(typeof(T))` is optimized away
|
||||
|
||||
if (typeof(Godot.Object).IsAssignableFrom(typeof(T)))
|
||||
return CreateFromGodotObject(UnsafeAs<Godot.Object>(from));
|
||||
|
||||
// `typeof(T).IsValueType` is optimized away
|
||||
// `typeof(T).IsEnum` is NOT optimized away: https://github.com/dotnet/runtime/issues/67113
|
||||
// Fortunately, `typeof(System.Enum).IsAssignableFrom(typeof(T))` does the job!
|
||||
|
||||
if (typeof(T).IsValueType && typeof(System.Enum).IsAssignableFrom(typeof(T)))
|
||||
{
|
||||
// `Type.GetTypeCode(typeof(T).GetEnumUnderlyingType())` is not optimized away.
|
||||
// Fortunately, `Unsafe.SizeOf<T>()` works and is optimized away.
|
||||
// We don't need to know whether it's signed or unsigned.
|
||||
|
||||
if (Unsafe.SizeOf<T>() == 1)
|
||||
return CreateFromInt(UnsafeAs<sbyte>(from));
|
||||
|
||||
if (Unsafe.SizeOf<T>() == 2)
|
||||
return CreateFromInt(UnsafeAs<short>(from));
|
||||
|
||||
if (Unsafe.SizeOf<T>() == 4)
|
||||
return CreateFromInt(UnsafeAs<int>(from));
|
||||
|
||||
if (Unsafe.SizeOf<T>() == 8)
|
||||
return CreateFromInt(UnsafeAs<long>(from));
|
||||
|
||||
throw UnsupportedType<T>();
|
||||
}
|
||||
|
||||
return GenericConversion<T>.ToVariant(from);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
[SuppressMessage("ReSharper", "RedundantNameQualifier")]
|
||||
public static T ConvertTo<[MustBeVariant] T>(in godot_variant variant)
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
static T UnsafeAsT<TFrom>(TFrom f) => Unsafe.As<TFrom, T>(ref Unsafe.AsRef(f));
|
||||
|
||||
if (typeof(T) == typeof(bool))
|
||||
return UnsafeAsT(ConvertToBool(variant));
|
||||
|
||||
if (typeof(T) == typeof(char))
|
||||
return UnsafeAsT(ConvertToChar(variant));
|
||||
|
||||
if (typeof(T) == typeof(sbyte))
|
||||
return UnsafeAsT(ConvertToInt8(variant));
|
||||
|
||||
if (typeof(T) == typeof(short))
|
||||
return UnsafeAsT(ConvertToInt16(variant));
|
||||
|
||||
if (typeof(T) == typeof(int))
|
||||
return UnsafeAsT(ConvertToInt32(variant));
|
||||
|
||||
if (typeof(T) == typeof(long))
|
||||
return UnsafeAsT(ConvertToInt64(variant));
|
||||
|
||||
if (typeof(T) == typeof(byte))
|
||||
return UnsafeAsT(ConvertToUInt8(variant));
|
||||
|
||||
if (typeof(T) == typeof(ushort))
|
||||
return UnsafeAsT(ConvertToUInt16(variant));
|
||||
|
||||
if (typeof(T) == typeof(uint))
|
||||
return UnsafeAsT(ConvertToUInt32(variant));
|
||||
|
||||
if (typeof(T) == typeof(ulong))
|
||||
return UnsafeAsT(ConvertToUInt64(variant));
|
||||
|
||||
if (typeof(T) == typeof(float))
|
||||
return UnsafeAsT(ConvertToFloat32(variant));
|
||||
|
||||
if (typeof(T) == typeof(double))
|
||||
return UnsafeAsT(ConvertToFloat64(variant));
|
||||
|
||||
if (typeof(T) == typeof(Vector2))
|
||||
return UnsafeAsT(ConvertToVector2(variant));
|
||||
|
||||
if (typeof(T) == typeof(Vector2i))
|
||||
return UnsafeAsT(ConvertToVector2i(variant));
|
||||
|
||||
if (typeof(T) == typeof(Rect2))
|
||||
return UnsafeAsT(ConvertToRect2(variant));
|
||||
|
||||
if (typeof(T) == typeof(Rect2i))
|
||||
return UnsafeAsT(ConvertToRect2i(variant));
|
||||
|
||||
if (typeof(T) == typeof(Transform2D))
|
||||
return UnsafeAsT(ConvertToTransform2D(variant));
|
||||
|
||||
if (typeof(T) == typeof(Vector3))
|
||||
return UnsafeAsT(ConvertToVector3(variant));
|
||||
|
||||
if (typeof(T) == typeof(Vector3i))
|
||||
return UnsafeAsT(ConvertToVector3i(variant));
|
||||
|
||||
if (typeof(T) == typeof(Basis))
|
||||
return UnsafeAsT(ConvertToBasis(variant));
|
||||
|
||||
if (typeof(T) == typeof(Quaternion))
|
||||
return UnsafeAsT(ConvertToQuaternion(variant));
|
||||
|
||||
if (typeof(T) == typeof(Transform3D))
|
||||
return UnsafeAsT(ConvertToTransform3D(variant));
|
||||
|
||||
if (typeof(T) == typeof(Vector4))
|
||||
return UnsafeAsT(ConvertToVector4(variant));
|
||||
|
||||
if (typeof(T) == typeof(Vector4i))
|
||||
return UnsafeAsT(ConvertToVector4i(variant));
|
||||
|
||||
if (typeof(T) == typeof(AABB))
|
||||
return UnsafeAsT(ConvertToAABB(variant));
|
||||
|
||||
if (typeof(T) == typeof(Color))
|
||||
return UnsafeAsT(ConvertToColor(variant));
|
||||
|
||||
if (typeof(T) == typeof(Plane))
|
||||
return UnsafeAsT(ConvertToPlane(variant));
|
||||
|
||||
if (typeof(T) == typeof(Callable))
|
||||
return UnsafeAsT(ConvertToCallableManaged(variant));
|
||||
|
||||
if (typeof(T) == typeof(SignalInfo))
|
||||
return UnsafeAsT(ConvertToSignalInfo(variant));
|
||||
|
||||
if (typeof(T) == typeof(string))
|
||||
return UnsafeAsT(ConvertToStringObject(variant));
|
||||
|
||||
if (typeof(T) == typeof(byte[]))
|
||||
return UnsafeAsT(ConvertAsPackedByteArrayToSystemArray(variant));
|
||||
|
||||
if (typeof(T) == typeof(int[]))
|
||||
return UnsafeAsT(ConvertAsPackedInt32ArrayToSystemArray(variant));
|
||||
|
||||
if (typeof(T) == typeof(long[]))
|
||||
return UnsafeAsT(ConvertAsPackedInt64ArrayToSystemArray(variant));
|
||||
|
||||
if (typeof(T) == typeof(float[]))
|
||||
return UnsafeAsT(ConvertAsPackedFloat32ArrayToSystemArray(variant));
|
||||
|
||||
if (typeof(T) == typeof(double[]))
|
||||
return UnsafeAsT(ConvertAsPackedFloat64ArrayToSystemArray(variant));
|
||||
|
||||
if (typeof(T) == typeof(string[]))
|
||||
return UnsafeAsT(ConvertAsPackedStringArrayToSystemArray(variant));
|
||||
|
||||
if (typeof(T) == typeof(Vector2[]))
|
||||
return UnsafeAsT(ConvertAsPackedVector2ArrayToSystemArray(variant));
|
||||
|
||||
if (typeof(T) == typeof(Vector3[]))
|
||||
return UnsafeAsT(ConvertAsPackedVector3ArrayToSystemArray(variant));
|
||||
|
||||
if (typeof(T) == typeof(Color[]))
|
||||
return UnsafeAsT(ConvertAsPackedColorArrayToSystemArray(variant));
|
||||
|
||||
if (typeof(T) == typeof(StringName[]))
|
||||
return UnsafeAsT(ConvertToSystemArrayOfStringName(variant));
|
||||
|
||||
if (typeof(T) == typeof(NodePath[]))
|
||||
return UnsafeAsT(ConvertToSystemArrayOfNodePath(variant));
|
||||
|
||||
if (typeof(T) == typeof(RID[]))
|
||||
return UnsafeAsT(ConvertToSystemArrayOfRID(variant));
|
||||
|
||||
if (typeof(T) == typeof(StringName))
|
||||
return UnsafeAsT(ConvertToStringNameObject(variant));
|
||||
|
||||
if (typeof(T) == typeof(NodePath))
|
||||
return UnsafeAsT(ConvertToNodePathObject(variant));
|
||||
|
||||
if (typeof(T) == typeof(RID))
|
||||
return UnsafeAsT(ConvertToRID(variant));
|
||||
|
||||
if (typeof(T) == typeof(Godot.Collections.Dictionary))
|
||||
return UnsafeAsT(ConvertToDictionaryObject(variant));
|
||||
|
||||
if (typeof(T) == typeof(Godot.Collections.Array))
|
||||
return UnsafeAsT(ConvertToArrayObject(variant));
|
||||
|
||||
if (typeof(T) == typeof(Variant))
|
||||
return UnsafeAsT(Variant.CreateCopyingBorrowed(variant));
|
||||
|
||||
// More complex checks here at the end, to avoid screwing the simple ones in case they're not optimized away.
|
||||
|
||||
// `typeof(X).IsAssignableFrom(typeof(T))` is optimized away
|
||||
|
||||
if (typeof(Godot.Object).IsAssignableFrom(typeof(T)))
|
||||
return (T)(object)ConvertToGodotObject(variant);
|
||||
|
||||
// `typeof(T).IsValueType` is optimized away
|
||||
// `typeof(T).IsEnum` is NOT optimized away: https://github.com/dotnet/runtime/issues/67113
|
||||
// Fortunately, `typeof(System.Enum).IsAssignableFrom(typeof(T))` does the job!
|
||||
|
||||
if (typeof(T).IsValueType && typeof(System.Enum).IsAssignableFrom(typeof(T)))
|
||||
{
|
||||
// `Type.GetTypeCode(typeof(T).GetEnumUnderlyingType())` is not optimized away.
|
||||
// Fortunately, `Unsafe.SizeOf<T>()` works and is optimized away.
|
||||
// We don't need to know whether it's signed or unsigned.
|
||||
|
||||
if (Unsafe.SizeOf<T>() == 1)
|
||||
return UnsafeAsT(ConvertToInt8(variant));
|
||||
|
||||
if (Unsafe.SizeOf<T>() == 2)
|
||||
return UnsafeAsT(ConvertToInt16(variant));
|
||||
|
||||
if (Unsafe.SizeOf<T>() == 4)
|
||||
return UnsafeAsT(ConvertToInt32(variant));
|
||||
|
||||
if (Unsafe.SizeOf<T>() == 8)
|
||||
return UnsafeAsT(ConvertToInt64(variant));
|
||||
|
||||
throw UnsupportedType<T>();
|
||||
}
|
||||
|
||||
return GenericConversion<T>.FromVariant(variant);
|
||||
}
|
||||
}
|
|
@ -120,6 +120,14 @@ public partial struct Variant : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Variant From<[MustBeVariant] T>(in T from) =>
|
||||
CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFrom(from));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public T As<[MustBeVariant] T>() =>
|
||||
VariantUtils.ConvertTo<T>(NativeVar.DangerousSelfRef);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool AsBool() =>
|
||||
VariantUtils.ConvertToBool((godot_variant)NativeVar);
|
|
@ -101,9 +101,9 @@
|
|||
<Compile Include="Core\NativeInterop\InteropUtils.cs" />
|
||||
<Compile Include="Core\NativeInterop\NativeFuncs.extended.cs" />
|
||||
<Compile Include="Core\NativeInterop\NativeVariantPtrArgs.cs" />
|
||||
<Compile Include="Core\NativeInterop\VariantConversionCallbacks.cs" />
|
||||
<Compile Include="Core\NativeInterop\VariantSpanHelpers.cs" />
|
||||
<Compile Include="Core\NativeInterop\VariantUtils.cs" />
|
||||
<Compile Include="Core\NativeInterop\VariantUtils.generic.cs" />
|
||||
<Compile Include="Core\NodePath.cs" />
|
||||
<Compile Include="Core\Object.base.cs" />
|
||||
<Compile Include="Core\Object.exceptions.cs" />
|
||||
|
@ -123,6 +123,7 @@
|
|||
<Compile Include="Core\StringName.cs" />
|
||||
<Compile Include="Core\Transform2D.cs" />
|
||||
<Compile Include="Core\Transform3D.cs" />
|
||||
<Compile Include="Core\Variant.cs" />
|
||||
<Compile Include="Core\Vector2.cs" />
|
||||
<Compile Include="Core\Vector2i.cs" />
|
||||
<Compile Include="Core\Vector3.cs" />
|
||||
|
@ -131,7 +132,6 @@
|
|||
<Compile Include="Core\Vector4i.cs" />
|
||||
<Compile Include="GlobalUsings.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Variant.cs" />
|
||||
</ItemGroup>
|
||||
<!--
|
||||
We import a props file with auto-generated includes. This works well with Rider.
|
||||
|
|
Loading…
Reference in New Issue