summaryrefslogtreecommitdiff
path: root/modules/mono/glue/GodotSharp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/mono/glue/GodotSharp')
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs32
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs5
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs74
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.generics.cs480
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs28
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs67
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs38
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs6
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeVariantPtrArgs.cs16
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs45
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj1
14 files changed, 709 insertions, 89 deletions
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
index 1c98dfcdf6..f1b46e293b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
@@ -489,25 +489,37 @@ namespace Godot.Collections
ICollection<T>,
IEnumerable<T>
{
+ private static godot_variant ToVariantFunc(in Array<T> godotArray) =>
+ VariantUtils.CreateFromArray(godotArray);
+
+ 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 unsafe delegate* managed<in T, godot_variant> _convertToVariantCallback;
- private static unsafe delegate* managed<in godot_variant, T> _convertToManagedCallback;
+ 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()
{
- _convertToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<T>();
- _convertToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<T>();
+ 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)
+ if (ConvertToVariantCallback == null || ConvertToManagedCallback == null)
{
throw new InvalidOperationException(
$"The array element type is not supported for conversion to Variant: '{typeof(T).FullName}'.");
@@ -653,7 +665,7 @@ namespace Godot.Collections
get
{
_underlyingArray.GetVariantBorrowElementAt(index, out godot_variant borrowElem);
- return _convertToManagedCallback(borrowElem);
+ return ConvertToManagedCallback(borrowElem);
}
set
{
@@ -663,7 +675,7 @@ namespace Godot.Collections
godot_variant* ptrw = NativeFuncs.godotsharp_array_ptrw(ref self);
godot_variant* itemPtr = &ptrw[index];
(*itemPtr).Dispose();
- *itemPtr = _convertToVariantCallback(value);
+ *itemPtr = ConvertToVariantCallback(value);
}
}
@@ -675,7 +687,7 @@ namespace Godot.Collections
/// <returns>The index of the item, or -1 if not found.</returns>
public unsafe int IndexOf(T item)
{
- using var variantValue = _convertToVariantCallback(item);
+ using var variantValue = ConvertToVariantCallback(item);
var self = (godot_array)_underlyingArray.NativeValue;
return NativeFuncs.godotsharp_array_index_of(ref self, variantValue);
}
@@ -693,7 +705,7 @@ namespace Godot.Collections
if (index < 0 || index > Count)
throw new ArgumentOutOfRangeException(nameof(index));
- using var variantValue = _convertToVariantCallback(item);
+ using var variantValue = ConvertToVariantCallback(item);
var self = (godot_array)_underlyingArray.NativeValue;
NativeFuncs.godotsharp_array_insert(ref self, index, variantValue);
}
@@ -726,7 +738,7 @@ namespace Godot.Collections
/// <returns>The new size after adding the item.</returns>
public unsafe void Add(T item)
{
- using var variantValue = _convertToVariantCallback(item);
+ using var variantValue = ConvertToVariantCallback(item);
var self = (godot_array)_underlyingArray.NativeValue;
_ = NativeFuncs.godotsharp_array_add(ref self, variantValue);
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs
index ae44f8f4ba..354212da1b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs
@@ -22,8 +22,7 @@ namespace Godot.Bridge
}
bool methodInvoked = godotObject.InvokeGodotClassMethod(CustomUnsafe.AsRef(method),
- new NativeVariantPtrArgs(args),
- argCount, out godot_variant retValue);
+ new NativeVariantPtrArgs(args, argCount), out godot_variant retValue);
if (!methodInvoked)
{
@@ -102,7 +101,7 @@ namespace Godot.Bridge
return godot_bool.False;
}
- *outRet = Marshaling.ConvertManagedObjectToVariant(ret);
+ *outRet = ret.CopyNativeVariant();
return godot_bool.True;
}
catch (Exception e)
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs
index 57240624bc..44ea8fc83d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs
@@ -9,7 +9,7 @@ namespace Godot.Bridge
{
// @formatter:off
public delegate* unmanaged<IntPtr, godot_variant**, int, godot_bool*, void> SignalAwaiter_SignalCallback;
- public delegate* unmanaged<IntPtr, godot_variant**, uint, godot_variant*, void> DelegateUtils_InvokeWithVariantArgs;
+ public delegate* unmanaged<IntPtr, void*, godot_variant**, int, godot_variant*, void> DelegateUtils_InvokeWithVariantArgs;
public delegate* unmanaged<IntPtr, IntPtr, godot_bool> DelegateUtils_DelegateEquals;
public delegate* unmanaged<IntPtr, godot_array*, godot_bool> DelegateUtils_TrySerializeDelegateWithGCHandle;
public delegate* unmanaged<godot_array*, IntPtr*, godot_bool> DelegateUtils_TryDeserializeDelegateWithGCHandle;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
index 092724a6b1..d83cf43eb2 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
@@ -339,7 +339,7 @@ namespace Godot.Bridge
*outOwnerIsNull = godot_bool.False;
owner.RaiseGodotClassSignalCallbacks(CustomUnsafe.AsRef(eventSignalName),
- new NativeVariantPtrArgs(args), argCount);
+ new NativeVariantPtrArgs(args, argCount));
}
catch (Exception e)
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs
index bdedd2e87a..f9309ca13e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs
@@ -26,11 +26,12 @@ namespace Godot
/// }
/// </code>
/// </example>
- public readonly struct Callable
+ public readonly partial struct Callable
{
private readonly Object _target;
private readonly StringName _method;
private readonly Delegate _delegate;
+ private readonly unsafe delegate* managed<object, NativeVariantPtrArgs, out godot_variant, void> _trampoline;
/// <summary>
/// Object that contains the method.
@@ -48,10 +49,10 @@ namespace Godot
public Delegate Delegate => _delegate;
/// <summary>
- /// Converts a <see cref="Delegate"/> to a <see cref="Callable"/>.
+ /// Trampoline function pointer for dynamically invoking <see cref="Callable.Delegate"/>.
/// </summary>
- /// <param name="delegate">The delegate to convert.</param>
- public static implicit operator Callable(Delegate @delegate) => new Callable(@delegate);
+ public unsafe delegate* managed<object, NativeVariantPtrArgs, out godot_variant, void> Trampoline
+ => _trampoline;
/// <summary>
/// Constructs a new <see cref="Callable"/> for the method called <paramref name="method"/>
@@ -59,22 +60,21 @@ namespace Godot
/// </summary>
/// <param name="target">Object that contains the method.</param>
/// <param name="method">Name of the method that will be called.</param>
- public Callable(Object target, StringName method)
+ public unsafe Callable(Object target, StringName method)
{
_target = target;
_method = method;
_delegate = null;
+ _trampoline = null;
}
- /// <summary>
- /// Constructs a new <see cref="Callable"/> for the given <paramref name="delegate"/>.
- /// </summary>
- /// <param name="delegate">Delegate method that will be called.</param>
- public Callable(Delegate @delegate)
+ private unsafe Callable(Delegate @delegate,
+ delegate* managed<object, NativeVariantPtrArgs, out godot_variant, void> trampoline)
{
_target = @delegate?.Target as Object;
_method = null;
_delegate = @delegate;
+ _trampoline = trampoline;
}
private const int VarArgsSpanThreshold = 5;
@@ -149,5 +149,59 @@ namespace Godot
NativeFuncs.godotsharp_callable_call_deferred(callable, (godot_variant**)argsPtr, argc);
}
}
+
+ /// <summary>
+ /// <para>
+ /// Constructs a new <see cref="Callable"/> using the <paramref name="trampoline"/>
+ /// function pointer to dynamically invoke the given <paramref name="delegate"/>.
+ /// </para>
+ /// <para>
+ /// The parameters passed to the <paramref name="trampoline"/> function are:
+ /// </para>
+ /// <list type="number">
+ /// <item>
+ /// <term>delegateObj</term>
+ /// <description>The given <paramref name="delegate"/>, upcast to <see cref="object"/>.</description>
+ /// </item>
+ /// <item>
+ /// <term>args</term>
+ /// <description>Array of <see cref="godot_variant"/> arguments.</description>
+ /// </item>
+ /// <item>
+ /// <term>ret</term>
+ /// <description>Return value of type <see cref="godot_variant"/>.</description>
+ /// </item>
+ ///</list>
+ /// <para>
+ /// The delegate should be downcast to a more specific delegate type before invoking.
+ /// </para>
+ /// </summary>
+ /// <example>
+ /// Usage example:
+ ///
+ /// <code>
+ /// static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ /// {
+ /// if (args.Count != 1)
+ /// throw new ArgumentException($&quot;Callable expected {1} arguments but received {args.Count}.&quot;);
+ ///
+ /// TResult res = ((Func&lt;int, string&gt;)delegateObj)(
+ /// VariantConversionCallbacks.GetToManagedCallback&lt;int&gt;()(args[0])
+ /// );
+ ///
+ /// ret = VariantConversionCallbacks.GetToVariantCallback&lt;string&gt;()(res);
+ /// }
+ ///
+ /// var callable = Callable.CreateWithUnsafeTrampoline((int num) =&gt; &quot;foo&quot; + num.ToString(), &amp;Trampoline);
+ /// var res = (string)callable.Call(10);
+ /// Console.WriteLine(res);
+ /// </code>
+ /// </example>
+ /// <param name="delegate">Delegate method that will be called.</param>
+ /// <param name="trampoline">Trampoline function pointer for invoking the delegate.</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe Callable CreateWithUnsafeTrampoline(Delegate @delegate,
+ delegate* managed<object, NativeVariantPtrArgs, out godot_variant, void> trampoline)
+ => new(@delegate, trampoline);
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.generics.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.generics.cs
new file mode 100644
index 0000000000..6c6a104019
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.generics.cs
@@ -0,0 +1,480 @@
+using System;
+using System.Runtime.CompilerServices;
+using Godot.NativeInterop;
+
+namespace Godot;
+
+#nullable enable
+
+public readonly partial struct Callable
+{
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static void ThrowIfArgCountMismatch(NativeVariantPtrArgs args, int countExpected,
+ [CallerArgumentExpression("args")] string? paramName = null)
+ {
+ if (countExpected != args.Count)
+ ThrowArgCountMismatch(countExpected, args.Count, paramName);
+
+ static void ThrowArgCountMismatch(int countExpected, int countReceived, string? paramName)
+ {
+ throw new ArgumentException(
+ "Invalid argument count for invoking callable." +
+ $" Expected {countExpected} arguments, received {countReceived}.",
+ paramName);
+ }
+ }
+
+ /// <summary>
+ /// Constructs a new <see cref="Callable"/> for the given <paramref name="action"/>.
+ /// </summary>
+ /// <param name="action">Action method that will be called.</param>
+ public static unsafe Callable From(
+ Action action
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 0);
+
+ ((Action)delegateObj)();
+
+ ret = default;
+ }
+
+ return CreateWithUnsafeTrampoline(action, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From(Action)"/>
+ public static unsafe Callable From<T0>(
+ Action<T0> action
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 1);
+
+ ((Action<T0>)delegateObj)(
+ VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0])
+ );
+
+ ret = default;
+ }
+
+ return CreateWithUnsafeTrampoline(action, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From(Action)"/>
+ public static unsafe Callable From<T0, T1>(
+ Action<T0, T1> action
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 2);
+
+ ((Action<T0, T1>)delegateObj)(
+ VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
+ VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1])
+ );
+
+ ret = default;
+ }
+
+ return CreateWithUnsafeTrampoline(action, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From(Action)"/>
+ public static unsafe Callable From<T0, T1, T2>(
+ Action<T0, T1, T2> action
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 3);
+
+ ((Action<T0, T1, T2>)delegateObj)(
+ VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
+ VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
+ VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2])
+ );
+
+ ret = default;
+ }
+
+ return CreateWithUnsafeTrampoline(action, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From(Action)"/>
+ public static unsafe Callable From<T0, T1, T2, T3>(
+ Action<T0, T1, T2, T3> action
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ 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])
+ );
+
+ ret = default;
+ }
+
+ return CreateWithUnsafeTrampoline(action, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From(Action)"/>
+ public static unsafe Callable From<T0, T1, T2, T3, T4>(
+ Action<T0, T1, T2, T3, T4> action
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ 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])
+ );
+
+ ret = default;
+ }
+
+ return CreateWithUnsafeTrampoline(action, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From(Action)"/>
+ public static unsafe Callable From<T0, T1, T2, T3, T4, T5>(
+ Action<T0, T1, T2, T3, T4, T5> action
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ 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])
+ );
+
+ ret = default;
+ }
+
+ return CreateWithUnsafeTrampoline(action, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From(Action)"/>
+ public static unsafe Callable From<T0, T1, T2, T3, T4, T5, T6>(
+ Action<T0, T1, T2, T3, T4, T5, T6> action
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ 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])
+ );
+
+ ret = default;
+ }
+
+ return CreateWithUnsafeTrampoline(action, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From(Action)"/>
+ public static unsafe Callable From<T0, T1, T2, T3, T4, T5, T6, T7>(
+ Action<T0, T1, T2, T3, T4, T5, T6, T7> action
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ 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])
+ );
+
+ ret = default;
+ }
+
+ return CreateWithUnsafeTrampoline(action, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From(Action)"/>
+ public static unsafe Callable From<T0, T1, T2, T3, T4, T5, T6, T7, T8>(
+ Action<T0, T1, T2, T3, T4, T5, T6, T7, T8> action
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ 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])
+ );
+
+ ret = default;
+ }
+
+ return CreateWithUnsafeTrampoline(action, &Trampoline);
+ }
+
+ /// <summary>
+ /// Constructs a new <see cref="Callable"/> for the given <paramref name="func"/>.
+ /// </summary>
+ /// <param name="func">Action method that will be called.</param>
+ public static unsafe Callable From<TResult>(
+ Func<TResult> func
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 0);
+
+ TResult res = ((Func<TResult>)delegateObj)();
+
+ ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ }
+
+ return CreateWithUnsafeTrampoline(func, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From{TResult}(Func{TResult})"/>
+ public static unsafe Callable From<T0, TResult>(
+ Func<T0, TResult> func
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 1);
+
+ TResult res = ((Func<T0, TResult>)delegateObj)(
+ VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0])
+ );
+
+ ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ }
+
+ return CreateWithUnsafeTrampoline(func, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From{TResult}(Func{TResult})"/>
+ public static unsafe Callable From<T0, T1, TResult>(
+ Func<T0, T1, TResult> func
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 2);
+
+ TResult res = ((Func<T0, T1, TResult>)delegateObj)(
+ VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
+ VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1])
+ );
+
+ ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ }
+
+ return CreateWithUnsafeTrampoline(func, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From{TResult}(Func{TResult})"/>
+ public static unsafe Callable From<T0, T1, T2, TResult>(
+ Func<T0, T1, T2, TResult> func
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ 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])
+ );
+
+ ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ }
+
+ return CreateWithUnsafeTrampoline(func, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From{TResult}(Func{TResult})"/>
+ public static unsafe Callable From<T0, T1, T2, T3, TResult>(
+ Func<T0, T1, T2, T3, TResult> func
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ 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])
+ );
+
+ ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ }
+
+ return CreateWithUnsafeTrampoline(func, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From{TResult}(Func{TResult})"/>
+ public static unsafe Callable From<T0, T1, T2, T3, T4, TResult>(
+ Func<T0, T1, T2, T3, T4, TResult> func
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ 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])
+ );
+
+ ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ }
+
+ return CreateWithUnsafeTrampoline(func, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From{TResult}(Func{TResult})"/>
+ public static unsafe Callable From<T0, T1, T2, T3, T4, T5, TResult>(
+ Func<T0, T1, T2, T3, T4, T5, TResult> func
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ 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])
+ );
+
+ ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ }
+
+ return CreateWithUnsafeTrampoline(func, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From{TResult}(Func{TResult})"/>
+ public static unsafe Callable From<T0, T1, T2, T3, T4, T5, T6, TResult>(
+ Func<T0, T1, T2, T3, T4, T5, T6, TResult> func
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ 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])
+ );
+
+ ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ }
+
+ return CreateWithUnsafeTrampoline(func, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From{TResult}(Func{TResult})"/>
+ public static unsafe Callable From<T0, T1, T2, T3, T4, T5, T6, T7, TResult>(
+ Func<T0, T1, T2, T3, T4, T5, T6, T7, TResult> func
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ 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])
+ );
+
+ ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ }
+
+ return CreateWithUnsafeTrampoline(func, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From{TResult}(Func{TResult})"/>
+ public static unsafe Callable From<T0, T1, T2, T3, T4, T5, T6, T7, T8, TResult>(
+ Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, TResult> func
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ 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])
+ );
+
+ ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ }
+
+ return CreateWithUnsafeTrampoline(func, &Trampoline);
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
index 9b3969d453..d19e0c08f2 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
@@ -30,33 +30,23 @@ namespace Godot
}
[UnmanagedCallersOnly]
- internal static unsafe void InvokeWithVariantArgs(IntPtr delegateGCHandle, godot_variant** args, uint argc,
- godot_variant* outRet)
+ internal static unsafe void InvokeWithVariantArgs(IntPtr delegateGCHandle, void* trampoline,
+ godot_variant** args, int argc, godot_variant* outRet)
{
try
{
- // TODO: Optimize
- var @delegate = (Delegate)GCHandle.FromIntPtr(delegateGCHandle).Target!;
- var managedArgs = new object?[argc];
-
- var parameterInfos = @delegate.Method.GetParameters();
- var paramsLength = parameterInfos.Length;
-
- if (argc != paramsLength)
+ if (trampoline == null)
{
- throw new InvalidOperationException(
- $"The delegate expects {paramsLength} arguments, but received {argc}.");
+ throw new ArgumentNullException(nameof(trampoline),
+ "Cannot dynamically invoke delegate because the trampoline is null.");
}
- for (uint i = 0; i < argc; i++)
- {
- managedArgs[i] = Marshaling.ConvertVariantToManagedObjectOfType(
- *args[i], parameterInfos[i].ParameterType);
- }
+ var @delegate = (Delegate)GCHandle.FromIntPtr(delegateGCHandle).Target!;
+ var trampolineFn = (delegate* managed<object, NativeVariantPtrArgs, out godot_variant, void>)trampoline;
- object? invokeRet = @delegate.DynamicInvoke(managedArgs);
+ trampolineFn(@delegate, new NativeVariantPtrArgs(args, argc), out godot_variant ret);
- *outRet = Marshaling.ConvertManagedObjectToVariant(invokeRet);
+ *outRet = ret;
}
catch (Exception e)
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
index 93103d0f6b..f8793332a0 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
@@ -356,35 +356,47 @@ namespace Godot.Collections
IDictionary<TKey, TValue>,
IReadOnlyDictionary<TKey, TValue>
{
+ private static godot_variant ToVariantFunc(in Dictionary<TKey, TValue> godotDictionary) =>
+ VariantUtils.CreateFromDictionary(godotDictionary);
+
+ 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 unsafe delegate* managed<in TKey, godot_variant> _convertKeyToVariantCallback;
- private static unsafe delegate* managed<in godot_variant, TKey> _convertKeyToManagedCallback;
- private static unsafe delegate* managed<in TValue, godot_variant> _convertValueToVariantCallback;
- private static unsafe delegate* managed<in godot_variant, TValue> _convertValueToManagedCallback;
+ 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()
{
- _convertKeyToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<TKey>();
- _convertKeyToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<TKey>();
- _convertValueToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<TValue>();
- _convertValueToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<TValue>();
+ 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)
+ 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)
+ if (ConvertValueToVariantCallback == null || ConvertValueToManagedCallback == null)
{
throw new InvalidOperationException(
$"The dictionary value type is not supported for conversion to Variant: '{typeof(TValue).FullName}'.");
@@ -473,14 +485,14 @@ namespace Godot.Collections
{
get
{
- using var variantKey = _convertKeyToVariantCallback(key);
+ using var variantKey = ConvertKeyToVariantCallback(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 ConvertValueToManagedCallback(value);
}
else
{
@@ -489,8 +501,8 @@ namespace Godot.Collections
}
set
{
- using var variantKey = _convertKeyToVariantCallback(key);
- using var variantValue = _convertValueToVariantCallback(value);
+ using var variantKey = ConvertKeyToVariantCallback(key);
+ using var variantValue = ConvertValueToVariantCallback(value);
var self = (godot_dictionary)_underlyingDict.NativeValue;
NativeFuncs.godotsharp_dictionary_set_value(ref self,
variantKey, variantValue);
@@ -539,8 +551,8 @@ namespace Godot.Collections
using (value)
{
return new KeyValuePair<TKey, TValue>(
- _convertKeyToManagedCallback(key),
- _convertValueToManagedCallback(value));
+ ConvertKeyToManagedCallback(key),
+ ConvertValueToManagedCallback(value));
}
}
@@ -552,13 +564,13 @@ namespace Godot.Collections
/// <param name="value">The object to add.</param>
public unsafe void Add(TKey key, TValue value)
{
- using var variantKey = _convertKeyToVariantCallback(key);
+ using var variantKey = ConvertKeyToVariantCallback(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 = ConvertValueToVariantCallback(value);
NativeFuncs.godotsharp_dictionary_add(ref self, variantKey, variantValue);
}
@@ -569,7 +581,7 @@ namespace Godot.Collections
/// <returns>Whether or not this dictionary contains the given key.</returns>
public unsafe bool ContainsKey(TKey key)
{
- using var variantKey = _convertKeyToVariantCallback(key);
+ using var variantKey = ConvertKeyToVariantCallback(key);
var self = (godot_dictionary)_underlyingDict.NativeValue;
return NativeFuncs.godotsharp_dictionary_contains_key(ref self, variantKey).ToBool();
}
@@ -580,7 +592,7 @@ namespace Godot.Collections
/// <param name="key">The key of the element to remove.</param>
public unsafe bool Remove(TKey key)
{
- using var variantKey = _convertKeyToVariantCallback(key);
+ using var variantKey = ConvertKeyToVariantCallback(key);
var self = (godot_dictionary)_underlyingDict.NativeValue;
return NativeFuncs.godotsharp_dictionary_remove_key(ref self, variantKey).ToBool();
}
@@ -593,13 +605,13 @@ namespace Godot.Collections
/// <returns>If an object was found for the given <paramref name="key"/>.</returns>
public unsafe bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
{
- using var variantKey = _convertKeyToVariantCallback(key);
+ using var variantKey = ConvertKeyToVariantCallback(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 ? ConvertValueToManagedCallback(retValue) : default;
return found;
}
@@ -625,7 +637,7 @@ namespace Godot.Collections
unsafe bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
{
- using var variantKey = _convertKeyToVariantCallback(item.Key);
+ using var variantKey = ConvertKeyToVariantCallback(item.Key);
var self = (godot_dictionary)_underlyingDict.NativeValue;
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
variantKey, out godot_variant retValue).ToBool();
@@ -635,7 +647,7 @@ namespace Godot.Collections
if (!found)
return false;
- using var variantValue = _convertValueToVariantCallback(item.Value);
+ using var variantValue = ConvertValueToVariantCallback(item.Value);
return NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool();
}
}
@@ -670,7 +682,7 @@ namespace Godot.Collections
unsafe bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
{
- using var variantKey = _convertKeyToVariantCallback(item.Key);
+ using var variantKey = ConvertKeyToVariantCallback(item.Key);
var self = (godot_dictionary)_underlyingDict.NativeValue;
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
variantKey, out godot_variant retValue).ToBool();
@@ -680,7 +692,7 @@ namespace Godot.Collections
if (!found)
return false;
- using var variantValue = _convertValueToVariantCallback(item.Value);
+ using var variantValue = ConvertValueToVariantCallback(item.Value);
if (NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool())
{
return NativeFuncs.godotsharp_dictionary_remove_key(
@@ -717,6 +729,7 @@ namespace Godot.Collections
public static implicit operator Variant(Dictionary<TKey, TValue> from) => Variant.CreateFrom(from);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static explicit operator Dictionary<TKey, TValue>(Variant from) => from.AsGodotDictionary<TKey, TValue>();
+ public static explicit operator Dictionary<TKey, TValue>(Variant from) =>
+ from.AsGodotDictionary<TKey, TValue>();
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
index 76b186cd15..649661ee06 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
@@ -721,10 +721,19 @@ namespace Godot.NativeInterop
if (p_managed_callable.Delegate != null)
{
var gcHandle = CustomGCHandle.AllocStrong(p_managed_callable.Delegate);
- IntPtr objectPtr = p_managed_callable.Target != null ? Object.GetPtr(p_managed_callable.Target) : IntPtr.Zero;
- NativeFuncs.godotsharp_callable_new_with_delegate(
- GCHandle.ToIntPtr(gcHandle), objectPtr, out godot_callable callable);
- return callable;
+
+ IntPtr objectPtr = p_managed_callable.Target != null ?
+ Object.GetPtr(p_managed_callable.Target) :
+ IntPtr.Zero;
+
+ unsafe
+ {
+ NativeFuncs.godotsharp_callable_new_with_delegate(
+ GCHandle.ToIntPtr(gcHandle), (IntPtr)p_managed_callable.Trampoline,
+ objectPtr, out godot_callable callable);
+
+ return callable;
+ }
}
else
{
@@ -748,19 +757,22 @@ namespace Godot.NativeInterop
public static Callable ConvertCallableToManaged(in godot_callable p_callable)
{
if (NativeFuncs.godotsharp_callable_get_data_for_marshalling(p_callable,
- out IntPtr delegateGCHandle, out IntPtr godotObject,
- out godot_string_name name).ToBool())
+ out IntPtr delegateGCHandle, out IntPtr trampoline,
+ out IntPtr godotObject, out godot_string_name name).ToBool())
{
if (delegateGCHandle != IntPtr.Zero)
{
- return new Callable((Delegate?)GCHandle.FromIntPtr(delegateGCHandle).Target);
- }
- else
- {
- return new Callable(
- InteropUtils.UnmanagedGetManaged(godotObject),
- StringName.CreateTakingOwnershipOfDisposableValue(name));
+ unsafe
+ {
+ return Callable.CreateWithUnsafeTrampoline(
+ (Delegate?)GCHandle.FromIntPtr(delegateGCHandle).Target,
+ (delegate* managed<object, NativeVariantPtrArgs, out godot_variant, void>)trampoline);
+ }
}
+
+ return new Callable(
+ InteropUtils.UnmanagedGetManaged(godotObject),
+ StringName.CreateTakingOwnershipOfDisposableValue(name));
}
// Some other unsupported callable
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
index 20ede9f0dd..088f4e7ecf 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
@@ -141,11 +141,11 @@ namespace Godot.NativeInterop
public static partial void godotsharp_packed_string_array_add(ref godot_packed_string_array r_dest,
in godot_string p_element);
- public static partial void godotsharp_callable_new_with_delegate(IntPtr p_delegate_handle, IntPtr p_object,
- out godot_callable r_callable);
+ public static partial void godotsharp_callable_new_with_delegate(IntPtr p_delegate_handle, IntPtr p_trampoline,
+ IntPtr p_object, out godot_callable r_callable);
internal static partial godot_bool godotsharp_callable_get_data_for_marshalling(in godot_callable p_callable,
- out IntPtr r_delegate_handle, out IntPtr r_object, out godot_string_name r_name);
+ out IntPtr r_delegate_handle, out IntPtr r_trampoline, out IntPtr r_object, out godot_string_name r_name);
internal static partial godot_variant godotsharp_callable_call(in godot_callable p_callable,
godot_variant** p_args, int p_arg_count, out godot_variant_call_error p_call_error);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeVariantPtrArgs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeVariantPtrArgs.cs
index 422df74c23..d8c5d99cb8 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeVariantPtrArgs.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeVariantPtrArgs.cs
@@ -8,8 +8,22 @@ namespace Godot.NativeInterop
public unsafe ref struct NativeVariantPtrArgs
{
private godot_variant** _args;
+ private int _argc;
- internal NativeVariantPtrArgs(godot_variant** args) => _args = args;
+ internal NativeVariantPtrArgs(godot_variant** args, int argc)
+ {
+ _args = args;
+ _argc = argc;
+ }
+
+ /// <summary>
+ /// Returns the number of arguments.
+ /// </summary>
+ public int Count
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _argc;
+ }
public ref godot_variant this[int index]
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs
index 9cde62c7c5..4b3db0c01a 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs
@@ -1,10 +1,15 @@
using System;
using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
namespace Godot.NativeInterop;
+// TODO: Change VariantConversionCallbacks<T>. Store the callback in a static field for quick repeated access, instead of checking every time.
internal static unsafe class VariantConversionCallbacks
{
+ internal static System.Collections.Generic.Dictionary<Type, (IntPtr ToVariant, IntPtr FromVariant)>
+ GenericConversionCallbacks = new();
+
[SuppressMessage("ReSharper", "RedundantNameQualifier")]
internal static delegate*<in T, godot_variant> GetToVariantCallback<T>()
{
@@ -502,6 +507,26 @@ internal static unsafe class VariantConversionCallbacks
&FromVariant;
}
+ // TODO:
+ // IsGenericType and GetGenericTypeDefinition don't work in NativeAOT's reflection-free mode.
+ // We could make the Godot collections implement an interface and use IsAssignableFrom instead.
+ // Or we could just skip the check and always look for a conversion callback for the type.
+ if (typeOfT.IsGenericType)
+ {
+ var genericTypeDef = typeOfT.GetGenericTypeDefinition();
+
+ if (genericTypeDef == typeof(Godot.Collections.Dictionary<,>) ||
+ genericTypeDef == typeof(Godot.Collections.Array<>))
+ {
+ RuntimeHelpers.RunClassConstructor(typeOfT.TypeHandle);
+
+ if (GenericConversionCallbacks.TryGetValue(typeOfT, out var genericConversion))
+ {
+ return (delegate*<in T, godot_variant>)genericConversion.ToVariant;
+ }
+ }
+ }
+
return null;
}
@@ -1005,6 +1030,26 @@ internal static unsafe class VariantConversionCallbacks
&ToVariant;
}
+ // TODO:
+ // IsGenericType and GetGenericTypeDefinition don't work in NativeAOT's reflection-free mode.
+ // We could make the Godot collections implement an interface and use IsAssignableFrom instead.
+ // Or we could just skip the check and always look for a conversion callback for the type.
+ if (typeOfT.IsGenericType)
+ {
+ var genericTypeDef = typeOfT.GetGenericTypeDefinition();
+
+ if (genericTypeDef == typeof(Godot.Collections.Dictionary<,>) ||
+ genericTypeDef == typeof(Godot.Collections.Array<>))
+ {
+ RuntimeHelpers.RunClassConstructor(typeOfT.TypeHandle);
+
+ if (GenericConversionCallbacks.TryGetValue(typeOfT, out var genericConversion))
+ {
+ return (delegate*<in godot_variant, T>)genericConversion.FromVariant;
+ }
+ }
+ }
+
// ReSharper restore RedundantCast
return null;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
index 5cb678c280..60ee6eb6f4 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
@@ -202,7 +202,7 @@ namespace Godot
// ReSharper disable once VirtualMemberNeverOverridden.Global
protected internal virtual void RaiseGodotClassSignalCallbacks(in godot_string_name signal,
- NativeVariantPtrArgs args, int argCount)
+ NativeVariantPtrArgs args)
{
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
index a63b668387..e3fb254f49 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
@@ -52,6 +52,7 @@
<Compile Include="Core\AABB.cs" />
<Compile Include="Core\Bridge\GodotSerializationInfo.cs" />
<Compile Include="Core\Bridge\MethodInfo.cs" />
+ <Compile Include="Core\Callable.generics.cs" />
<Compile Include="Core\CustomGCHandle.cs" />
<Compile Include="Core\Array.cs" />
<Compile Include="Core\Attributes\AssemblyHasScriptsAttribute.cs" />