diff options
author | Ignacio Roldán Etcheverry <ignalfonsore@gmail.com> | 2021-12-28 23:25:16 +0100 |
---|---|---|
committer | Ignacio Roldán Etcheverry <ignalfonsore@gmail.com> | 2022-08-22 03:36:51 +0200 |
commit | e5e7a795b14487e7eb0cfb011a8e0518769ce533 (patch) | |
tree | 57a0322ef0c11d8944f9a95708d243dcc3e4c5a4 /modules/mono/glue/GodotSharp | |
parent | 34db8d2c6c4d2c714772479145c235c9f4189bdb (diff) |
C#: Code cleanup and greatly reduce use of C# pointers
Diffstat (limited to 'modules/mono/glue/GodotSharp')
37 files changed, 1968 insertions, 1209 deletions
diff --git a/modules/mono/glue/GodotSharp/.editorconfig b/modules/mono/glue/GodotSharp/.editorconfig new file mode 100644 index 0000000000..d4e71b1bd9 --- /dev/null +++ b/modules/mono/glue/GodotSharp/.editorconfig @@ -0,0 +1,8 @@ +[**/Generated/**.cs] +# Validate parameter is non-null before using it +# Useful for generated code, as it disables nullable +dotnet_diagnostic.CA1062.severity = error +# CA1069: Enums should not have duplicate values +dotnet_diagnostic.CA1069.severity = none +# CA1708: Identifiers should differ by more than case +dotnet_diagnostic.CA1708.severity = none diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs index 2aa2ece803..9fa221a0cc 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Collections; using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; using Godot.NativeInterop; namespace Godot.Collections @@ -14,14 +15,14 @@ namespace Godot.Collections /// </summary> public sealed class Array : IList, IDisposable { - public godot_array NativeValue; + internal godot_array.movable NativeValue; /// <summary> /// Constructs a new empty <see cref="Array"/>. /// </summary> public Array() { - NativeValue = NativeFuncs.godotsharp_array_new(); + NativeValue = (godot_array.movable)NativeFuncs.godotsharp_array_new(); } /// <summary> @@ -32,7 +33,7 @@ namespace Godot.Collections public Array(IEnumerable collection) : this() { if (collection == null) - throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'"); + throw new ArgumentNullException(nameof(collection)); foreach (object element in collection) Add(element); @@ -47,9 +48,9 @@ namespace Godot.Collections public Array(params object[] array) : this() { if (array == null) - throw new NullReferenceException($"Parameter '{nameof(array)} cannot be null.'"); + throw new ArgumentNullException(nameof(array)); - NativeValue = NativeFuncs.godotsharp_array_new(); + NativeValue = (godot_array.movable)NativeFuncs.godotsharp_array_new(); int length = array.Length; Resize(length); @@ -60,7 +61,9 @@ namespace Godot.Collections private Array(godot_array nativeValueToOwn) { - NativeValue = nativeValueToOwn; + NativeValue = (godot_array.movable)(nativeValueToOwn.IsAllocated ? + nativeValueToOwn : + NativeFuncs.godotsharp_array_new()); } // Explicit name to make it very clear @@ -84,7 +87,7 @@ namespace Godot.Collections public void Dispose(bool disposing) { // Always dispose `NativeValue` even if disposing is true - NativeValue.Dispose(); + NativeValue.DangerousSelfRef.Dispose(); } /// <summary> @@ -95,7 +98,8 @@ namespace Godot.Collections public Array Duplicate(bool deep = false) { godot_array newArray; - NativeFuncs.godotsharp_array_duplicate(ref NativeValue, deep.ToGodotBool(), out newArray); + var self = (godot_array)NativeValue; + NativeFuncs.godotsharp_array_duplicate(ref self, deep.ToGodotBool(), out newArray); return CreateTakingOwnershipOfDisposableValue(newArray); } @@ -104,12 +108,20 @@ namespace Godot.Collections /// </summary> /// <param name="newSize">The new size of the array.</param> /// <returns><see cref="Error.Ok"/> if successful, or an error code.</returns> - public Error Resize(int newSize) => NativeFuncs.godotsharp_array_resize(ref NativeValue, newSize); + public Error Resize(int newSize) + { + var self = (godot_array)NativeValue; + return NativeFuncs.godotsharp_array_resize(ref self, newSize); + } /// <summary> /// Shuffles the contents of this <see cref="Array"/> into a random order. /// </summary> - public void Shuffle() => NativeFuncs.godotsharp_array_shuffle(ref NativeValue); + public void Shuffle() + { + var self = (godot_array)NativeValue; + NativeFuncs.godotsharp_array_shuffle(ref self); + } /// <summary> /// Concatenates these two <see cref="Array"/>s. @@ -119,6 +131,17 @@ namespace Godot.Collections /// <returns>A new Godot Array with the contents of both arrays.</returns> public static Array operator +(Array left, Array right) { + if (left == null) + { + if (right == null) + return new Array(); + + return right.Duplicate(deep: false); + } + + if (right == null) + return left.Duplicate(deep: false); + int leftCount = left.Count; int rightCount = right.Count; @@ -146,14 +169,15 @@ namespace Godot.Collections get { GetVariantBorrowElementAt(index, out godot_variant borrowElem); - return Marshaling.variant_to_mono_object(&borrowElem); + return Marshaling.ConvertVariantToManagedObject(borrowElem); } set { if (index < 0 || index >= Count) - throw new IndexOutOfRangeException(); - godot_variant* ptrw = NativeFuncs.godotsharp_array_ptrw(ref NativeValue); - ptrw[index] = Marshaling.mono_object_to_variant(value); + throw new ArgumentOutOfRangeException(nameof(index)); + var self = (godot_array)NativeValue; + godot_variant* ptrw = NativeFuncs.godotsharp_array_ptrw(ref self); + ptrw[index] = Marshaling.ConvertManagedObjectToVariant(value); } } @@ -163,10 +187,11 @@ namespace Godot.Collections /// </summary> /// <param name="value">The object to add.</param> /// <returns>The new size after adding the object.</returns> - public unsafe int Add(object value) + public int Add(object value) { - using godot_variant variantValue = Marshaling.mono_object_to_variant(value); - return NativeFuncs.godotsharp_array_add(ref NativeValue, &variantValue); + using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(value); + var self = (godot_array)NativeValue; + return NativeFuncs.godotsharp_array_add(ref self, variantValue); } /// <summary> @@ -187,10 +212,11 @@ namespace Godot.Collections /// </summary> /// <param name="value">The object to search for.</param> /// <returns>The index of the object, or -1 if not found.</returns> - public unsafe int IndexOf(object value) + public int IndexOf(object value) { - using godot_variant variantValue = Marshaling.mono_object_to_variant(value); - return NativeFuncs.godotsharp_array_index_of(ref NativeValue, &variantValue); + using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(value); + var self = (godot_array)NativeValue; + return NativeFuncs.godotsharp_array_index_of(ref self, variantValue); } /// <summary> @@ -201,13 +227,14 @@ namespace Godot.Collections /// </summary> /// <param name="index">The index to insert at.</param> /// <param name="value">The object to insert.</param> - public unsafe void Insert(int index, object value) + public void Insert(int index, object value) { if (index < 0 || index > Count) - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); - using godot_variant variantValue = Marshaling.mono_object_to_variant(value); - NativeFuncs.godotsharp_array_insert(ref NativeValue, index, &variantValue); + using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(value); + var self = (godot_array)NativeValue; + NativeFuncs.godotsharp_array_insert(ref self, index, variantValue); } /// <summary> @@ -229,9 +256,10 @@ namespace Godot.Collections public void RemoveAt(int index) { if (index < 0 || index > Count) - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); - NativeFuncs.godotsharp_array_remove_at(ref NativeValue, index); + var self = (godot_array)NativeValue; + NativeFuncs.godotsharp_array_remove_at(ref self, index); } // ICollection @@ -241,7 +269,7 @@ namespace Godot.Collections /// This is also known as the size or length of the array. /// </summary> /// <returns>The number of elements.</returns> - public int Count => NativeValue.Size; + public int Count => NativeValue.DangerousSelfRef.Size; object ICollection.SyncRoot => this; @@ -252,21 +280,21 @@ namespace Godot.Collections /// untyped C# array, starting at the given index. /// </summary> /// <param name="array">The array to copy to.</param> - /// <param name="destIndex">The index to start at.</param> - public void CopyTo(System.Array array, int destIndex) + /// <param name="index">The index to start at.</param> + public void CopyTo(System.Array array, int index) { if (array == null) throw new ArgumentNullException(nameof(array), "Value cannot be null."); - if (destIndex < 0) + if (index < 0) { - throw new ArgumentOutOfRangeException(nameof(destIndex), + throw new ArgumentOutOfRangeException(nameof(index), "Number was less than the array's lower bound in the first dimension."); } int count = Count; - if (array.Length < (destIndex + count)) + if (array.Length < (index + count)) { throw new ArgumentException( "Destination array was not long enough. Check destIndex and length, and the array's lower bounds."); @@ -276,9 +304,9 @@ namespace Godot.Collections { for (int i = 0; i < count; i++) { - object obj = Marshaling.variant_to_mono_object(&(*NativeValue._p)._arrayVector._ptr[i]); - array.SetValue(obj, destIndex); - destIndex++; + object obj = Marshaling.ConvertVariantToManagedObject(NativeValue.DangerousSelfRef.Elements[i]); + array.SetValue(obj, index); + index++; } } } @@ -303,11 +331,12 @@ namespace Godot.Collections /// Converts this <see cref="Array"/> to a string. /// </summary> /// <returns>A string representation of this array.</returns> - public override unsafe string ToString() + public override string ToString() { - using godot_string str = default; - NativeFuncs.godotsharp_array_to_string(ref NativeValue, &str); - return Marshaling.mono_string_from_godot(str); + var self = (godot_array)NativeValue; + NativeFuncs.godotsharp_array_to_string(ref self, out godot_string str); + using (str) + return Marshaling.ConvertStringToManaged(str); } /// <summary> @@ -316,7 +345,7 @@ namespace Godot.Collections internal void GetVariantBorrowElementAt(int index, out godot_variant elem) { if (index < 0 || index >= Count) - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); GetVariantBorrowElementAtUnchecked(index, out elem); } @@ -325,7 +354,7 @@ namespace Godot.Collections /// </summary> internal unsafe void GetVariantBorrowElementAtUnchecked(int index, out godot_variant elem) { - elem = (*NativeValue._p)._arrayVector._ptr[index]; + elem = NativeValue.DangerousSelfRef.Elements[index]; } } @@ -344,11 +373,16 @@ namespace Godot.Collections /// </summary> /// <typeparam name="T">The type of the array.</typeparam> [SuppressMessage("ReSharper", "RedundantExtendsListEntry")] + [SuppressMessage("Naming", "CA1710", MessageId = "Identifiers should have correct suffix")] public sealed class Array<T> : IList<T>, ICollection<T>, IEnumerable<T>, IGenericGodotArray { private readonly Array _underlyingArray; - internal ref godot_array NativeValue => ref _underlyingArray.NativeValue; + internal ref godot_array.movable NativeValue + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _underlyingArray.NativeValue; + } // ReSharper disable StaticMemberInGenericType // Warning is about unique static fields being created for each generic type combination: @@ -376,7 +410,7 @@ namespace Godot.Collections public Array(IEnumerable<T> collection) { if (collection == null) - throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'"); + throw new ArgumentNullException(nameof(collection)); _underlyingArray = new Array(collection); } @@ -389,9 +423,7 @@ namespace Godot.Collections public Array(params T[] array) : this() { if (array == null) - { - throw new NullReferenceException($"Parameter '{nameof(array)} cannot be null.'"); - } + throw new ArgumentNullException(nameof(array)); _underlyingArray = new Array(array); } @@ -415,7 +447,7 @@ namespace Godot.Collections /// <param name="from">The typed array to convert.</param> public static explicit operator Array(Array<T> from) { - return from._underlyingArray; + return from?._underlyingArray; } /// <summary> @@ -454,6 +486,17 @@ namespace Godot.Collections /// <returns>A new Godot Array with the contents of both arrays.</returns> public static Array<T> operator +(Array<T> left, Array<T> right) { + if (left == null) + { + if (right == null) + return new Array<T>(); + + return right.Duplicate(deep: false); + } + + if (right == null) + return left.Duplicate(deep: false); + return new Array<T>(left._underlyingArray + right._underlyingArray); } @@ -468,10 +511,7 @@ namespace Godot.Collections get { _underlyingArray.GetVariantBorrowElementAt(index, out godot_variant borrowElem); - unsafe - { - return (T)Marshaling.variant_to_mono_object_of_type(&borrowElem, TypeOfElements); - } + return (T)Marshaling.ConvertVariantToManagedObjectOfType(borrowElem, TypeOfElements); } set => _underlyingArray[index] = value; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs index 437878818c..e1e2df199b 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs @@ -167,7 +167,7 @@ namespace Godot case 2: return Column2; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(column)); } } set @@ -184,7 +184,7 @@ namespace Godot Column2 = value; return; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(column)); } } } @@ -386,7 +386,7 @@ namespace Godot case 2: return Row2; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } @@ -413,7 +413,7 @@ namespace Godot Row2 = value; return; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs index db27989bdb..6bb1ba27e9 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs @@ -18,22 +18,24 @@ namespace Godot.Bridge if (godotObject == null) { *ret = default; - (*refCallError).error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INSTANCE_IS_NULL; + (*refCallError).Error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INSTANCE_IS_NULL; return false.ToGodotBool(); } - using godot_string dest = default; - NativeFuncs.godotsharp_string_name_as_string(&dest, method); - string methodStr = Marshaling.mono_string_from_godot(dest); + NativeFuncs.godotsharp_string_name_as_string(out godot_string dest, CustomUnsafe.AsRef(method)); + string methodStr; + using (dest) + methodStr = Marshaling.ConvertStringToManaged(dest); - bool methodInvoked = godotObject.InternalGodotScriptCall(methodStr, args, argCount, out godot_variant retValue); + bool methodInvoked = godotObject.InternalGodotScriptCall(methodStr, new NativeVariantPtrArgs(args), + argCount, out godot_variant retValue); if (!methodInvoked) { *ret = default; // This is important, as it tells Object::call that no method was called. // Otherwise, it would prevent Object::call from calling native methods. - (*refCallError).error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INVALID_METHOD; + (*refCallError).Error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INVALID_METHOD; return false.ToGodotBool(); } @@ -60,12 +62,15 @@ namespace Godot.Bridge throw new InvalidOperationException(); var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue( - NativeFuncs.godotsharp_string_name_new_copy(name)); + NativeFuncs.godotsharp_string_name_new_copy(CustomUnsafe.AsRef(name))); - if (godotObject.InternalGodotScriptSetFieldOrPropViaReflection(nameManaged.ToString(), value)) + if (godotObject.InternalGodotScriptSetFieldOrPropViaReflection( + nameManaged.ToString(), CustomUnsafe.AsRef(value))) + { return true.ToGodotBool(); + } - object valueManaged = Marshaling.variant_to_mono_object(value); + object valueManaged = Marshaling.ConvertVariantToManagedObject(CustomUnsafe.AsRef(value)); return godotObject._Set(nameManaged, valueManaged).ToGodotBool(); } @@ -89,10 +94,10 @@ namespace Godot.Bridge throw new InvalidOperationException(); var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue( - NativeFuncs.godotsharp_string_name_new_copy(name)); + NativeFuncs.godotsharp_string_name_new_copy(CustomUnsafe.AsRef(name))); if (godotObject.InternalGodotScriptGetFieldOrPropViaReflection(nameManaged.ToString(), - out godot_variant outRetValue)) + out godot_variant outRetValue)) { *outRet = outRetValue; return true.ToGodotBool(); @@ -106,7 +111,7 @@ namespace Godot.Bridge return false.ToGodotBool(); } - *outRet = Marshaling.mono_object_to_variant(ret); + *outRet = Marshaling.ConvertManagedObjectToVariant(ret); return true.ToGodotBool(); } catch (Exception e) @@ -158,7 +163,7 @@ namespace Godot.Bridge return; } - *outRes = Marshaling.mono_string_to_godot(resultStr); + *outRes = Marshaling.ConvertStringToNative(resultStr); *outValid = true.ToGodotBool(); } catch (Exception e) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs index 9655887e52..689d6cddbb 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs @@ -104,8 +104,8 @@ namespace Godot.Bridge for (int i = 0; i < paramCount; i++) { - invokeParams[i] = Marshaling.variant_to_mono_object_of_type( - args[i], parameters[i].ParameterType); + invokeParams[i] = Marshaling.ConvertVariantToManagedObjectOfType( + *args[i], parameters[i].ParameterType); } ctor.Invoke(obj, invokeParams); @@ -149,7 +149,7 @@ namespace Godot.Bridge return; } - *outRes = NativeFuncs.godotsharp_string_name_new_copy(nativeName.NativeValue); + *outRes = NativeFuncs.godotsharp_string_name_new_copy((godot_string_name)nativeName.NativeValue); } catch (Exception e) { @@ -177,7 +177,7 @@ namespace Godot.Bridge { // Performance is not critical here as this will be replaced with a generated dictionary. using var stringName = StringName.CreateTakingOwnershipOfDisposableValue( - NativeFuncs.godotsharp_string_name_new_copy(nativeTypeName)); + NativeFuncs.godotsharp_string_name_new_copy(CustomUnsafe.AsRef(nativeTypeName))); string nativeTypeNameStr = stringName.ToString(); if (nativeTypeNameStr[0] == '_') @@ -277,7 +277,8 @@ namespace Godot.Bridge *outOwnerIsNull = false.ToGodotBool(); - owner.InternalRaiseEventSignal(eventSignalName, args, argCount); + owner.InternalRaiseEventSignal(CustomUnsafe.AsRef(eventSignalName), + new NativeVariantPtrArgs(args), argCount); } catch (Exception e) { @@ -302,9 +303,10 @@ namespace Godot.Bridge // Legacy signals foreach (var signalDelegate in top - .GetNestedTypes(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public) - .Where(nestedType => typeof(Delegate).IsAssignableFrom(nestedType)) - .Where(@delegate => @delegate.GetCustomAttributes().OfType<SignalAttribute>().Any())) + .GetNestedTypes(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | + BindingFlags.Public) + .Where(nestedType => typeof(Delegate).IsAssignableFrom(nestedType)) + .Where(@delegate => @delegate.GetCustomAttributes().OfType<SignalAttribute>().Any())) { var invokeMethod = signalDelegate.GetMethod("Invoke"); @@ -315,7 +317,7 @@ namespace Godot.Bridge foreach (var parameters in invokeMethod.GetParameters()) { - var paramType = Marshaling.managed_to_variant_type( + var paramType = Marshaling.ConvertManagedTypeToVariantType( parameters.ParameterType, out bool nilIsVariant); signalParams.Add(new Dictionary() { @@ -341,8 +343,8 @@ namespace Godot.Bridge BindingFlags.NonPublic | BindingFlags.Public); foreach (var eventSignalField in fields - .Where(f => typeof(Delegate).IsAssignableFrom(f.FieldType)) - .Where(f => foundEventSignals.Contains(f.Name))) + .Where(f => typeof(Delegate).IsAssignableFrom(f.FieldType)) + .Where(f => foundEventSignals.Contains(f.Name))) { var delegateType = eventSignalField.FieldType; var invokeMethod = delegateType.GetMethod("Invoke"); @@ -354,7 +356,7 @@ namespace Godot.Bridge foreach (var parameters in invokeMethod.GetParameters()) { - var paramType = Marshaling.managed_to_variant_type( + var paramType = Marshaling.ConvertManagedTypeToVariantType( parameters.ParameterType, out bool nilIsVariant); signalParams.Add(new Dictionary() { @@ -370,7 +372,7 @@ namespace Godot.Bridge top = top.BaseType; } - *outRetSignals = NativeFuncs.godotsharp_dictionary_new_copy(signals.NativeValue); + *outRetSignals = NativeFuncs.godotsharp_dictionary_new_copy((godot_dictionary)signals.NativeValue); } catch (Exception e) { @@ -387,7 +389,7 @@ namespace Godot.Bridge // Performance is not critical here as this will be replaced with source generators. using var signals = new Dictionary(); - string signalNameStr = Marshaling.mono_string_from_godot(*signalName); + string signalNameStr = Marshaling.ConvertStringToManaged(*signalName); Type top = _scriptBridgeMap[scriptPtr]; Type native = Object.InternalGetClassNativeBase(top); @@ -401,7 +403,7 @@ namespace Godot.Bridge .Where(nestedType => typeof(Delegate).IsAssignableFrom(nestedType)) .Where(@delegate => @delegate.GetCustomAttributes().OfType<SignalAttribute>().Any()) .Any(signalDelegate => signalDelegate.Name == signalNameStr) - ) + ) { return true.ToGodotBool(); } @@ -413,7 +415,7 @@ namespace Godot.Bridge BindingFlags.NonPublic | BindingFlags.Public) .Where(ev => ev.GetCustomAttributes().OfType<SignalAttribute>().Any()) .Any(eventSignal => eventSignal.Name == signalNameStr) - ) + ) { return true.ToGodotBool(); } @@ -440,7 +442,7 @@ namespace Godot.Bridge if (!_scriptBridgeMap.TryGetValue(scriptPtr, out var scriptType)) return false.ToGodotBool(); - string methodStr = Marshaling.mono_string_from_godot(*method); + string methodStr = Marshaling.ConvertStringToManaged(*method); if (deep.ToBool()) { @@ -517,7 +519,7 @@ namespace Godot.Bridge { try { - string scriptPathStr = Marshaling.mono_string_from_godot(*scriptPath); + string scriptPathStr = Marshaling.ConvertStringToManaged(*scriptPath); if (!_scriptLookupMap.TryGetValue(scriptPathStr, out var lookupInfo)) return false.ToGodotBool(); @@ -612,7 +614,8 @@ namespace Godot.Bridge } *outRpcFunctionsDest = - NativeFuncs.godotsharp_dictionary_new_copy(((Dictionary)rpcFunctions).NativeValue); + NativeFuncs.godotsharp_dictionary_new_copy( + (godot_dictionary)((Dictionary)rpcFunctions).NativeValue); } catch (Exception e) { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs index 2722b64e6d..ef75ff446a 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs @@ -1,5 +1,7 @@ using System; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Godot.NativeInterop; namespace Godot { @@ -24,7 +26,7 @@ namespace Godot /// } /// </code> /// </example> - public struct Callable + public readonly struct Callable { private readonly Object _target; private readonly StringName _method; @@ -34,10 +36,12 @@ namespace Godot /// Object that contains the method. /// </summary> public Object Target => _target; + /// <summary> /// Name of the method that will be called. /// </summary> public StringName Method => _method; + /// <summary> /// Delegate of the method that will be called. /// </summary> @@ -73,15 +77,43 @@ namespace Godot _delegate = @delegate; } + private const int VarArgsSpanThreshold = 5; + /// <summary> /// Calls the method represented by this <see cref="Callable"/>. /// Arguments can be passed and should match the method's signature. /// </summary> /// <param name="args">Arguments that will be passed to the method call.</param> /// <returns>The value returned by the method.</returns> - public object Call(params object[] args) + public unsafe object Call(params object[] args) { - return godot_icall_Callable_Call(ref this, args); + using godot_callable callable = Marshaling.ConvertCallableToNative(this); + + int argc = args.Length; + + Span<godot_variant.movable> argsStoreSpan = argc <= VarArgsSpanThreshold ? + stackalloc godot_variant.movable[VarArgsSpanThreshold].Cleared() : + new godot_variant.movable[argc]; + + Span<IntPtr> argsSpan = argc <= 10 ? + stackalloc IntPtr[argc] : + new IntPtr[argc]; + + using var variantSpanDisposer = new VariantSpanDisposer(argsStoreSpan); + + fixed (godot_variant* varargs = &MemoryMarshal.GetReference(argsStoreSpan).DangerousSelfRef) + fixed (IntPtr* argsPtr = &MemoryMarshal.GetReference(argsSpan)) + { + for (int i = 0; i < argc; i++) + { + varargs[i] = Marshaling.ConvertManagedObjectToVariant(args[i]); + argsPtr[i] = new IntPtr(&varargs[i]); + } + + using godot_variant ret = NativeFuncs.godotsharp_callable_call(callable, + (godot_variant**)argsPtr, argc, out _); + return Marshaling.ConvertVariantToManagedObject(ret); + } } /// <summary> @@ -89,9 +121,33 @@ namespace Godot /// Arguments can be passed and should match the method's signature. /// </summary> /// <param name="args">Arguments that will be passed to the method call.</param> - public void CallDeferred(params object[] args) + public unsafe void CallDeferred(params object[] args) { - godot_icall_Callable_CallDeferred(ref this, args); + using godot_callable callable = Marshaling.ConvertCallableToNative(this); + + int argc = args.Length; + + Span<godot_variant.movable> argsStoreSpan = argc <= VarArgsSpanThreshold ? + stackalloc godot_variant.movable[VarArgsSpanThreshold].Cleared() : + new godot_variant.movable[argc]; + + Span<IntPtr> argsSpan = argc <= 10 ? + stackalloc IntPtr[argc] : + new IntPtr[argc]; + + using var variantSpanDisposer = new VariantSpanDisposer(argsStoreSpan); + + fixed (godot_variant* varargs = &MemoryMarshal.GetReference(argsStoreSpan).DangerousSelfRef) + fixed (IntPtr* argsPtr = &MemoryMarshal.GetReference(argsSpan)) + { + for (int i = 0; i < argc; i++) + { + varargs[i] = Marshaling.ConvertManagedObjectToVariant(args[i]); + argsPtr[i] = new IntPtr(&varargs[i]); + } + + NativeFuncs.godotsharp_callable_call_deferred(callable, (godot_variant**)argsPtr, argc); + } } [MethodImpl(MethodImplOptions.InternalCall)] diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs index a6324504fc..ed0e1efd35 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs @@ -210,7 +210,7 @@ namespace Godot case 3: return a; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } set @@ -230,7 +230,7 @@ namespace Godot a = value; return; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } } @@ -841,7 +841,7 @@ namespace Godot return ParseCol4(str, ofs) * 16 + ParseCol4(str, ofs + 1); } - private string ToHex32(float val) + private static string ToHex32(float val) { byte b = (byte)Mathf.RoundToInt(Mathf.Clamp(val * 255, 0, 255)); return b.HexEncode(); @@ -849,7 +849,7 @@ namespace Godot internal static bool HtmlIsValid(string color) { - if (color.Length == 0) + if (string.IsNullOrEmpty(color)) { return false; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs index e446b3db1c..39904b6154 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs @@ -18,7 +18,7 @@ namespace Godot else sb.Append(type); - sb.Append(" "); + sb.Append(' '); } [UnmanagedCallersOnly] @@ -55,15 +55,15 @@ namespace Godot if (methodBase is MethodInfo) sb.AppendTypeName(((MethodInfo)methodBase).ReturnType); - sb.Append(methodBase.DeclaringType.FullName); - sb.Append("."); + sb.Append(methodBase.DeclaringType?.FullName ?? "<unknown>"); + sb.Append('.'); sb.Append(methodBase.Name); if (methodBase.IsGenericMethod) { Type[] genericParams = methodBase.GetGenericArguments(); - sb.Append("<"); + sb.Append('<'); for (int j = 0; j < genericParams.Length; j++) { @@ -73,10 +73,10 @@ namespace Godot sb.AppendTypeName(genericParams[j]); } - sb.Append(">"); + sb.Append('>'); } - sb.Append("("); + sb.Append('('); bool varArgs = (methodBase.CallingConvention & CallingConventions.VarArgs) != 0; @@ -93,7 +93,7 @@ namespace Godot sb.AppendTypeName(parameter[i].ParameterType); } - sb.Append(")"); + sb.Append(')'); methodDecl = sb.ToString(); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs index 87c93e35f5..02ae392f47 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs @@ -48,13 +48,13 @@ namespace Godot for (uint i = 0; i < argc; i++) { - managedArgs[i] = Marshaling.variant_to_mono_object_of_type( - args[i], parameterInfos[i].ParameterType); + managedArgs[i] = Marshaling.ConvertVariantToManagedObjectOfType( + *args[i], parameterInfos[i].ParameterType); } object invokeRet = @delegate.DynamicInvoke(managedArgs); - *outRet = Marshaling.mono_object_to_variant(invokeRet); + *outRet = Marshaling.ConvertManagedObjectToVariant(invokeRet); } catch (Exception e) { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs index c21d53b4d4..89fc2210b8 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections; using Godot.NativeInterop; using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; namespace Godot.Collections { @@ -15,14 +16,14 @@ namespace Godot.Collections IDictionary, IDisposable { - public godot_dictionary NativeValue; + internal godot_dictionary.movable NativeValue; /// <summary> /// Constructs a new empty <see cref="Dictionary"/>. /// </summary> public Dictionary() { - NativeValue = NativeFuncs.godotsharp_dictionary_new(); + NativeValue = (godot_dictionary.movable)NativeFuncs.godotsharp_dictionary_new(); } /// <summary> @@ -33,7 +34,7 @@ namespace Godot.Collections public Dictionary(IDictionary dictionary) : this() { if (dictionary == null) - throw new NullReferenceException($"Parameter '{nameof(dictionary)} cannot be null.'"); + throw new ArgumentNullException(nameof(dictionary)); foreach (DictionaryEntry entry in dictionary) Add(entry.Key, entry.Value); @@ -41,7 +42,9 @@ namespace Godot.Collections private Dictionary(godot_dictionary nativeValueToOwn) { - NativeValue = nativeValueToOwn; + NativeValue = (godot_dictionary.movable)(nativeValueToOwn.IsAllocated ? + nativeValueToOwn : + NativeFuncs.godotsharp_dictionary_new()); } // Explicit name to make it very clear @@ -65,7 +68,7 @@ namespace Godot.Collections public void Dispose(bool disposing) { // Always dispose `NativeValue` even if disposing is true - NativeValue.Dispose(); + NativeValue.DangerousSelfRef.Dispose(); } /// <summary> @@ -76,7 +79,8 @@ namespace Godot.Collections public Dictionary Duplicate(bool deep = false) { godot_dictionary newDictionary; - NativeFuncs.godotsharp_dictionary_duplicate(ref NativeValue, deep.ToGodotBool(), out newDictionary); + var self = (godot_dictionary)NativeValue; + NativeFuncs.godotsharp_dictionary_duplicate(ref self, deep.ToGodotBool(), out newDictionary); return CreateTakingOwnershipOfDisposableValue(newDictionary); } @@ -90,7 +94,8 @@ namespace Godot.Collections get { godot_array keysArray; - NativeFuncs.godotsharp_dictionary_keys(ref NativeValue, out keysArray); + var self = (godot_dictionary)NativeValue; + NativeFuncs.godotsharp_dictionary_keys(ref self, out keysArray); return Array.CreateTakingOwnershipOfDisposableValue(keysArray); } } @@ -103,22 +108,25 @@ namespace Godot.Collections get { godot_array valuesArray; - NativeFuncs.godotsharp_dictionary_values(ref NativeValue, out valuesArray); + var self = (godot_dictionary)NativeValue; + NativeFuncs.godotsharp_dictionary_values(ref self, out valuesArray); return Array.CreateTakingOwnershipOfDisposableValue(valuesArray); } } private (Array keys, Array values, int count) GetKeyValuePairs() { + var self = (godot_dictionary)NativeValue; + godot_array keysArray; - NativeFuncs.godotsharp_dictionary_keys(ref NativeValue, out keysArray); + NativeFuncs.godotsharp_dictionary_keys(ref self, out keysArray); var keys = Array.CreateTakingOwnershipOfDisposableValue(keysArray); godot_array valuesArray; - NativeFuncs.godotsharp_dictionary_keys(ref NativeValue, out valuesArray); + NativeFuncs.godotsharp_dictionary_keys(ref self, out valuesArray); var values = Array.CreateTakingOwnershipOfDisposableValue(valuesArray); - int count = NativeFuncs.godotsharp_dictionary_count(ref NativeValue); + int count = NativeFuncs.godotsharp_dictionary_count(ref self); return (keys, values, count); } @@ -131,16 +139,17 @@ namespace Godot.Collections /// Returns the object at the given <paramref name="key"/>. /// </summary> /// <value>The object at the given <paramref name="key"/>.</value> - public unsafe object this[object key] + public object this[object key] { get { - using godot_variant variantKey = Marshaling.mono_object_to_variant(key); - if (NativeFuncs.godotsharp_dictionary_try_get_value(ref NativeValue, &variantKey, - out godot_variant value).ToBool()) + using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); + var self = (godot_dictionary)NativeValue; + if (NativeFuncs.godotsharp_dictionary_try_get_value(ref self, variantKey, + out godot_variant value).ToBool()) { using (value) - return Marshaling.variant_to_mono_object(&value); + return Marshaling.ConvertVariantToManagedObject(value); } else { @@ -149,9 +158,10 @@ namespace Godot.Collections } set { - using godot_variant variantKey = Marshaling.mono_object_to_variant(key); - using godot_variant variantValue = Marshaling.mono_object_to_variant(value); - NativeFuncs.godotsharp_dictionary_set_value(ref NativeValue, &variantKey, &variantValue); + using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); + using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(value); + var self = (godot_dictionary)NativeValue; + NativeFuncs.godotsharp_dictionary_set_value(ref self, variantKey, variantValue); } } @@ -161,31 +171,38 @@ 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(object key, object value) + public void Add(object key, object value) { - using godot_variant variantKey = Marshaling.mono_object_to_variant(key); + using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); + + var self = (godot_dictionary)NativeValue; - if (NativeFuncs.godotsharp_dictionary_contains_key(ref NativeValue, &variantKey).ToBool()) + if (NativeFuncs.godotsharp_dictionary_contains_key(ref self, variantKey).ToBool()) throw new ArgumentException("An element with the same key already exists", nameof(key)); - using godot_variant variantValue = Marshaling.mono_object_to_variant(value); - NativeFuncs.godotsharp_dictionary_add(ref NativeValue, &variantKey, &variantValue); + using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(value); + NativeFuncs.godotsharp_dictionary_add(ref self, variantKey, variantValue); } /// <summary> /// Erases all items from this <see cref="Dictionary"/>. /// </summary> - public void Clear() => NativeFuncs.godotsharp_dictionary_clear(ref NativeValue); + public void Clear() + { + var self = (godot_dictionary)NativeValue; + NativeFuncs.godotsharp_dictionary_clear(ref self); + } /// <summary> /// Checks if this <see cref="Dictionary"/> contains the given key. /// </summary> /// <param name="key">The key to look for.</param> /// <returns>Whether or not this dictionary contains the given key.</returns> - public unsafe bool Contains(object key) + public bool Contains(object key) { - using godot_variant variantKey = Marshaling.mono_object_to_variant(key); - return NativeFuncs.godotsharp_dictionary_contains_key(ref NativeValue, &variantKey).ToBool(); + using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); + var self = (godot_dictionary)NativeValue; + return NativeFuncs.godotsharp_dictionary_contains_key(ref self, variantKey).ToBool(); } /// <summary> @@ -198,10 +215,11 @@ namespace Godot.Collections /// Removes an element from this <see cref="Dictionary"/> by key. /// </summary> /// <param name="key">The key of the element to remove.</param> - public unsafe void Remove(object key) + public void Remove(object key) { - using godot_variant variantKey = Marshaling.mono_object_to_variant(key); - NativeFuncs.godotsharp_dictionary_remove_key(ref NativeValue, &variantKey); + using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); + var self = (godot_dictionary)NativeValue; + NativeFuncs.godotsharp_dictionary_remove_key(ref self, variantKey); } // ICollection @@ -215,7 +233,14 @@ namespace Godot.Collections /// This is also known as the size or length of the dictionary. /// </summary> /// <returns>The number of elements.</returns> - public int Count => NativeFuncs.godotsharp_dictionary_count(ref NativeValue); + public int Count + { + get + { + var self = (godot_dictionary)NativeValue; + return NativeFuncs.godotsharp_dictionary_count(ref self); + } + } /// <summary> /// Copies the elements of this <see cref="Dictionary"/> to the given @@ -279,17 +304,19 @@ namespace Godot.Collections } } - private unsafe void UpdateEntry() + private void UpdateEntry() { _dirty = false; - NativeFuncs.godotsharp_dictionary_key_value_pair_at(ref _dictionary.NativeValue, _index, + var self = (godot_dictionary)_dictionary.NativeValue; + NativeFuncs.godotsharp_dictionary_key_value_pair_at(ref self, _index, out godot_variant key, out godot_variant value); using (key) using (value) { - _entry = new DictionaryEntry(Marshaling.variant_to_mono_object(&key), - Marshaling.variant_to_mono_object(&value)); + // FIXME: DictionaryEntry keys cannot be null, but Godot dictionaries allow null keys + _entry = new DictionaryEntry(Marshaling.ConvertVariantToManagedObject(key)!, + Marshaling.ConvertVariantToManagedObject(value)); } } @@ -315,11 +342,12 @@ namespace Godot.Collections /// Converts this <see cref="Dictionary"/> to a string. /// </summary> /// <returns>A string representation of this dictionary.</returns> - public override unsafe string ToString() + public override string ToString() { - using godot_string str = default; - NativeFuncs.godotsharp_dictionary_to_string(ref NativeValue, &str); - return Marshaling.mono_string_from_godot(str); + var self = (godot_dictionary)NativeValue; + NativeFuncs.godotsharp_dictionary_to_string(ref self, out godot_string str); + using (str) + return Marshaling.ConvertStringToManaged(str); } } @@ -345,7 +373,11 @@ namespace Godot.Collections { private readonly Dictionary _underlyingDict; - internal ref godot_dictionary NativeValue => ref _underlyingDict.NativeValue; + internal ref godot_dictionary.movable NativeValue + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _underlyingDict.NativeValue; + } // ReSharper disable StaticMemberInGenericType // Warning is about unique static fields being created for each generic type combination: @@ -375,10 +407,10 @@ namespace Godot.Collections /// <returns>A new Godot Dictionary.</returns> public Dictionary(IDictionary<TKey, TValue> dictionary) { - _underlyingDict = new Dictionary(); - if (dictionary == null) - throw new NullReferenceException($"Parameter '{nameof(dictionary)} cannot be null.'"); + throw new ArgumentNullException(nameof(dictionary)); + + _underlyingDict = new Dictionary(); foreach (KeyValuePair<TKey, TValue> entry in dictionary) Add(entry.Key, entry.Value); @@ -405,7 +437,7 @@ namespace Godot.Collections /// <param name="from">The typed dictionary to convert.</param> public static explicit operator Dictionary(Dictionary<TKey, TValue> from) { - return from._underlyingDict; + return from?._underlyingDict; } /// <summary> @@ -428,19 +460,17 @@ namespace Godot.Collections { get { - unsafe + using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); + var self = (godot_dictionary)_underlyingDict.NativeValue; + if (NativeFuncs.godotsharp_dictionary_try_get_value(ref self, + variantKey, out godot_variant value).ToBool()) { - using godot_variant variantKey = Marshaling.mono_object_to_variant(key); - if (NativeFuncs.godotsharp_dictionary_try_get_value(ref _underlyingDict.NativeValue, - &variantKey, out godot_variant value).ToBool()) - { - using (value) - return (TValue)Marshaling.variant_to_mono_object_of_type(&value, TypeOfValues); - } - else - { - throw new KeyNotFoundException(); - } + using (value) + return (TValue)Marshaling.ConvertVariantToManagedObjectOfType(value, TypeOfValues); + } + else + { + throw new KeyNotFoundException(); } } set => _underlyingDict[key] = value; @@ -454,7 +484,8 @@ namespace Godot.Collections get { godot_array keyArray; - NativeFuncs.godotsharp_dictionary_keys(ref _underlyingDict.NativeValue, out keyArray); + var self = (godot_dictionary)_underlyingDict.NativeValue; + NativeFuncs.godotsharp_dictionary_keys(ref self, out keyArray); return Array<TKey>.CreateTakingOwnershipOfDisposableValue(keyArray); } } @@ -467,21 +498,23 @@ namespace Godot.Collections get { godot_array valuesArray; - NativeFuncs.godotsharp_dictionary_values(ref _underlyingDict.NativeValue, out valuesArray); + var self = (godot_dictionary)_underlyingDict.NativeValue; + NativeFuncs.godotsharp_dictionary_values(ref self, out valuesArray); return Array<TValue>.CreateTakingOwnershipOfDisposableValue(valuesArray); } } - private unsafe KeyValuePair<TKey, TValue> GetKeyValuePair(int index) + private KeyValuePair<TKey, TValue> GetKeyValuePair(int index) { - NativeFuncs.godotsharp_dictionary_key_value_pair_at(ref _underlyingDict.NativeValue, index, + var self = (godot_dictionary)_underlyingDict.NativeValue; + NativeFuncs.godotsharp_dictionary_key_value_pair_at(ref self, index, out godot_variant key, out godot_variant value); using (key) using (value) { - return new KeyValuePair<TKey, TValue>((TKey)Marshaling.variant_to_mono_object(&key), - (TValue)Marshaling.variant_to_mono_object(&value)); + return new KeyValuePair<TKey, TValue>((TKey)Marshaling.ConvertVariantToManagedObject(key), + (TValue)Marshaling.ConvertVariantToManagedObject(value)); } } @@ -510,10 +543,11 @@ 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 godot_variant variantKey = Marshaling.mono_object_to_variant(key); - return NativeFuncs.godotsharp_dictionary_remove_key(ref _underlyingDict.NativeValue, &variantKey).ToBool(); + using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); + var self = (godot_dictionary)_underlyingDict.NativeValue; + return NativeFuncs.godotsharp_dictionary_remove_key(ref self, variantKey).ToBool(); } /// <summary> @@ -522,16 +556,17 @@ 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 godot_variant variantKey = Marshaling.mono_object_to_variant(key); - bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref _underlyingDict.NativeValue, - &variantKey, out godot_variant retValue).ToBool(); + using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key); + var self = (godot_dictionary)_underlyingDict.NativeValue; + bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self, + variantKey, out godot_variant retValue).ToBool(); using (retValue) { value = found ? - (TValue)Marshaling.variant_to_mono_object_of_type(&retValue, TypeOfValues) : + (TValue)Marshaling.ConvertVariantToManagedObjectOfType(retValue, TypeOfValues) : default; } @@ -562,19 +597,20 @@ namespace Godot.Collections _underlyingDict.Clear(); } - unsafe bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item) + bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item) { - using godot_variant variantKey = Marshaling.mono_object_to_variant(item.Key); - bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref _underlyingDict.NativeValue, - &variantKey, out godot_variant retValue).ToBool(); + using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(item.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) { if (!found) return false; - using godot_variant variantValue = Marshaling.mono_object_to_variant(item.Value); - return NativeFuncs.godotsharp_variant_equals(&variantValue, &retValue).ToBool(); + using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(item.Value); + return NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool(); } } @@ -606,22 +642,23 @@ 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 godot_variant variantKey = Marshaling.mono_object_to_variant(item.Key); - bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref _underlyingDict.NativeValue, - &variantKey, out godot_variant retValue).ToBool(); + using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(item.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) { if (!found) return false; - using godot_variant variantValue = Marshaling.mono_object_to_variant(item.Value); - if (NativeFuncs.godotsharp_variant_equals(&variantValue, &retValue).ToBool()) + using godot_variant variantValue = Marshaling.ConvertManagedObjectToVariant(item.Value); + if (NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool()) { return NativeFuncs.godotsharp_dictionary_remove_key( - ref _underlyingDict.NativeValue, &variantKey).ToBool(); + ref self, variantKey).ToBool(); } return false; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs index 340780bb45..4094ceeb22 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs @@ -35,17 +35,14 @@ namespace Godot if (!IsInstanceValid(obj)) return null; - using godot_ref weakRef = default; - - unsafe + NativeFuncs.godotsharp_weakref(GetPtr(obj), out godot_ref weakRef); + using (weakRef) { - NativeFuncs.godotsharp_weakref(GetPtr(obj), &weakRef); - } + if (weakRef.IsNull) + return null; - if (weakRef.IsNull) - return null; - - return (WeakRef)InteropUtils.UnmanagedGetManaged(weakRef._reference); + return (WeakRef)InteropUtils.UnmanagedGetManaged(weakRef.Reference); + } } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs index 17bca19fab..fa8a1c6402 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using Godot.Collections; using Godot.NativeInterop; @@ -11,7 +10,7 @@ namespace Godot /// Returns a list of all nodes assigned to the given <paramref name="group"/>. /// </summary> /// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam> - public unsafe Array<T> GetNodesInGroup<T>(StringName group) where T : class + public Array<T> GetNodesInGroup<T>(StringName group) where T : class { var array = GetNodesInGroup(group); @@ -29,19 +28,18 @@ namespace Godot BindingFlags.Public | BindingFlags.NonPublic); var nativeName = (StringName)field!.GetValue(null); - godot_string_name nativeNameAux = nativeName.NativeValue; - godot_array inputAux = array.NativeValue; - godot_array filteredArray; - NativeFuncs.godotsharp_array_filter_godot_objects_by_native( - &nativeNameAux, &inputAux, &filteredArray); + var nativeNameSelf = (godot_string_name)nativeName!.NativeValue; + var inputSelf = (godot_array)array.NativeValue; + NativeFuncs.godotsharp_array_filter_godot_objects_by_native(nativeNameSelf, inputSelf, + out godot_array filteredArray); return Array<T>.CreateTakingOwnershipOfDisposableValue(filteredArray); } else { // Custom derived type - godot_array inputAux = array.NativeValue; - godot_array filteredArray; - NativeFuncs.godotsharp_array_filter_godot_objects_by_non_native(&inputAux, &filteredArray); + var inputSelf = (godot_array)array.NativeValue; + NativeFuncs.godotsharp_array_filter_godot_objects_by_non_native(inputSelf, + out godot_array filteredArray); var filteredArrayWrapped = Array.CreateTakingOwnershipOfDisposableValue(filteredArray); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs index 39271d3daf..02ae32f46e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs @@ -26,12 +26,12 @@ namespace Godot /// <param name="bytes">Byte array that will be decoded to a <c>Variant</c>.</param> /// <param name="allowObjects">If objects should be decoded.</param> /// <returns>The decoded <c>Variant</c>.</returns> - public static unsafe object Bytes2Var(byte[] bytes, bool allowObjects = false) + public static object Bytes2Var(byte[] bytes, bool allowObjects = false) { - using var varBytes = Marshaling.mono_array_to_PackedByteArray(bytes); - using godot_variant ret = default; - NativeFuncs.godotsharp_bytes2var(&varBytes, allowObjects.ToGodotBool(), &ret); - return Marshaling.variant_to_mono_object(&ret); + using var varBytes = Marshaling.ConvertSystemArrayToNativePackedByteArray(bytes); + NativeFuncs.godotsharp_bytes2var(varBytes, allowObjects.ToGodotBool(), out godot_variant ret); + using (ret) + return Marshaling.ConvertVariantToManagedObject(ret); } /// <summary> @@ -49,12 +49,12 @@ namespace Godot /// </code> /// </example> /// <returns>The <c>Variant</c> converted to the given <paramref name="type"/>.</returns> - public static unsafe object Convert(object what, Variant.Type type) + public static object Convert(object what, Variant.Type type) { - using var whatVariant = Marshaling.mono_object_to_variant(what); - using godot_variant ret = default; - NativeFuncs.godotsharp_convert(&whatVariant, (int)type, &ret); - return Marshaling.variant_to_mono_object(&ret); + using var whatVariant = Marshaling.ConvertManagedObjectToVariant(what); + NativeFuncs.godotsharp_convert(whatVariant, (int)type, out godot_variant ret); + using (ret) + return Marshaling.ConvertVariantToManagedObject(ret); } /// <summary> @@ -88,10 +88,10 @@ namespace Godot /// </example> /// <param name="var">Variable that will be hashed.</param> /// <returns>Hash of the variable passed.</returns> - public static unsafe int Hash(object var) + public static int Hash(object var) { - using var variant = Marshaling.mono_object_to_variant(var); - return NativeFuncs.godotsharp_hash(&variant); + using var variant = Marshaling.ConvertManagedObjectToVariant(var); + return NativeFuncs.godotsharp_hash(variant); } /// <summary> @@ -207,10 +207,10 @@ namespace Godot /// </code> /// </example> /// <param name="message">Error message.</param> - public static unsafe void PushError(string message) + public static void PushError(string message) { - using var godotStr = Marshaling.mono_string_to_godot(message); - NativeFuncs.godotsharp_pusherror(&godotStr); + using var godotStr = Marshaling.ConvertStringToNative(message); + NativeFuncs.godotsharp_pusherror(godotStr); } /// <summary> @@ -220,10 +220,10 @@ namespace Godot /// GD.PushWarning("test warning"); // Prints "test warning" to debugger and terminal as warning call /// </example> /// <param name="message">Warning message.</param> - public static unsafe void PushWarning(string message) + public static void PushWarning(string message) { - using var godotStr = Marshaling.mono_string_to_godot(message); - NativeFuncs.godotsharp_pushwarning(&godotStr); + using var godotStr = Marshaling.ConvertStringToNative(message); + NativeFuncs.godotsharp_pushwarning(godotStr); } /// <summary> @@ -242,11 +242,11 @@ namespace Godot /// </code> /// </example> /// <param name="what">Arguments that will be printed.</param> - public static unsafe void Print(params object[] what) + public static void Print(params object[] what) { string str = string.Concat(GetPrintParams(what)); - using var godotStr = Marshaling.mono_string_to_godot(str); - NativeFuncs.godotsharp_print(&godotStr); + using var godotStr = Marshaling.ConvertStringToNative(str); + NativeFuncs.godotsharp_print(godotStr); } /// <summary> @@ -273,11 +273,11 @@ namespace Godot /// </code> /// </example> /// <param name="what">Arguments that will be printed.</param> - public static unsafe void PrintRich(params object[] what) + public static void PrintRich(params object[] what) { string str = string.Concat(GetPrintParams(what)); - using var godotStr = Marshaling.mono_string_to_godot(str); - NativeFuncs.godotsharp_print_rich(&godotStr); + using var godotStr = Marshaling.ConvertStringToNative(str); + NativeFuncs.godotsharp_print_rich(godotStr); } /// <summary> @@ -297,11 +297,11 @@ namespace Godot /// </code> /// </example> /// <param name="what">Arguments that will be printed.</param> - public static unsafe void PrintErr(params object[] what) + public static void PrintErr(params object[] what) { string str = string.Concat(GetPrintParams(what)); - using var godotStr = Marshaling.mono_string_to_godot(str); - NativeFuncs.godotsharp_printerr(&godotStr); + using var godotStr = Marshaling.ConvertStringToNative(str); + NativeFuncs.godotsharp_printerr(godotStr); } /// <summary> @@ -319,11 +319,11 @@ namespace Godot /// </code> /// </example> /// <param name="what">Arguments that will be printed.</param> - public static unsafe void PrintRaw(params object[] what) + public static void PrintRaw(params object[] what) { string str = string.Concat(GetPrintParams(what)); - using var godotStr = Marshaling.mono_string_to_godot(str); - NativeFuncs.godotsharp_printraw(&godotStr); + using var godotStr = Marshaling.ConvertStringToNative(str); + NativeFuncs.godotsharp_printraw(godotStr); } /// <summary> @@ -335,11 +335,11 @@ namespace Godot /// </code> /// </example> /// <param name="what">Arguments that will be printed.</param> - public static unsafe void PrintS(params object[] what) + public static void PrintS(params object[] what) { string str = string.Join(' ', GetPrintParams(what)); - using var godotStr = Marshaling.mono_string_to_godot(str); - NativeFuncs.godotsharp_prints(&godotStr); + using var godotStr = Marshaling.ConvertStringToNative(str); + NativeFuncs.godotsharp_prints(godotStr); } /// <summary> @@ -351,11 +351,11 @@ namespace Godot /// </code> /// </example> /// <param name="what">Arguments that will be printed.</param> - public static unsafe void PrintT(params object[] what) + public static void PrintT(params object[] what) { string str = string.Join('\t', GetPrintParams(what)); - using var godotStr = Marshaling.mono_string_to_godot(str); - NativeFuncs.godotsharp_printt(&godotStr); + using var godotStr = Marshaling.ConvertStringToNative(str); + NativeFuncs.godotsharp_printt(godotStr); } /// <summary> @@ -520,12 +520,12 @@ namespace Godot /// </summary> /// <param name="what">Arguments that will converted to string.</param> /// <returns>The string formed by the given arguments.</returns> - public static unsafe string Str(params object[] what) + public static string Str(params object[] what) { - using var whatGodotArray = Marshaling.mono_array_to_Array(what); - using godot_string ret = default; - NativeFuncs.godotsharp_str(&whatGodotArray, &ret); - return Marshaling.mono_string_from_godot(ret); + using var whatGodotArray = Marshaling.ConvertSystemArrayToNativeGodotArray(what); + NativeFuncs.godotsharp_str(whatGodotArray, out godot_string ret); + using (ret) + return Marshaling.ConvertStringToManaged(ret); } /// <summary> @@ -540,12 +540,12 @@ namespace Godot /// </example> /// <param name="str">String that will be converted to Variant.</param> /// <returns>The decoded <c>Variant</c>.</returns> - public static unsafe object Str2Var(string str) + public static object Str2Var(string str) { - using var godotStr = Marshaling.mono_string_to_godot(str); - using godot_variant ret = default; - NativeFuncs.godotsharp_str2var(&godotStr, &ret); - return Marshaling.variant_to_mono_object(&ret); + using var godotStr = Marshaling.ConvertStringToNative(str); + NativeFuncs.godotsharp_str2var(godotStr, out godot_variant ret); + using (ret) + return Marshaling.ConvertVariantToManagedObject(ret); } /// <summary> @@ -557,13 +557,12 @@ namespace Godot /// <param name="var">Variant that will be encoded.</param> /// <param name="fullObjects">If objects should be serialized.</param> /// <returns>The <c>Variant</c> encoded as an array of bytes.</returns> - public static unsafe byte[] Var2Bytes(object var, bool fullObjects = false) + public static byte[] Var2Bytes(object var, bool fullObjects = false) { - using var variant = Marshaling.mono_object_to_variant(var); - using godot_packed_byte_array varBytes = default; - NativeFuncs.godotsharp_var2bytes(&variant, fullObjects.ToGodotBool(), &varBytes); + using var variant = Marshaling.ConvertManagedObjectToVariant(var); + NativeFuncs.godotsharp_var2bytes(variant, fullObjects.ToGodotBool(), out var varBytes); using (varBytes) - return Marshaling.PackedByteArray_to_mono_array(&varBytes); + return Marshaling.ConvertNativePackedByteArrayToSystemArray(varBytes); } /// <summary> @@ -583,12 +582,12 @@ namespace Godot /// </example> /// <param name="var">Variant that will be converted to string.</param> /// <returns>The <c>Variant</c> encoded as a string.</returns> - public static unsafe string Var2Str(object var) + public static string Var2Str(object var) { - using var variant = Marshaling.mono_object_to_variant(var); - using godot_string ret = default; - NativeFuncs.godotsharp_var2str(&variant, &ret); - return Marshaling.mono_string_from_godot(ret); + using var variant = Marshaling.ConvertManagedObjectToVariant(var); + NativeFuncs.godotsharp_var2str(variant, out godot_string ret); + using (ret) + return Marshaling.ConvertStringToManaged(ret); } /// <summary> @@ -597,7 +596,7 @@ namespace Godot /// <returns>The <see cref="Variant.Type"/> for the given <paramref name="type"/>.</returns> public static Variant.Type TypeToVariantType(Type type) { - return Marshaling.managed_to_variant_type(type, out bool _); + return Marshaling.ConvertManagedTypeToVariantType(type, out bool _); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs index 0942d8f722..ef20819d62 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs @@ -10,7 +10,10 @@ using System.Runtime.InteropServices; namespace Godot.NativeInterop { - internal static class GodotBoolExtensions + // NOTES: + // ref structs cannot implement interfaces, but they still work in `using` directives if they declare Dispose() + + public static class GodotBoolExtensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe godot_bool ToGodotBool(this bool @bool) @@ -35,9 +38,9 @@ namespace Godot.NativeInterop [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_ref : IDisposable + public ref struct godot_ref { - internal IntPtr _reference; + private IntPtr _reference; public void Dispose() { @@ -47,7 +50,17 @@ namespace Godot.NativeInterop _reference = IntPtr.Zero; } - public bool IsNull => _reference == IntPtr.Zero; + public readonly IntPtr Reference + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _reference; + } + + public readonly bool IsNull + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _reference == IntPtr.Zero; + } } [SuppressMessage("ReSharper", "InconsistentNaming")] @@ -63,41 +76,53 @@ namespace Godot.NativeInterop [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_variant_call_error + public ref struct godot_variant_call_error { - public godot_variant_call_error_error error; - public int argument; - public int expected; + private godot_variant_call_error_error error; + private int argument; + private int expected; + + public godot_variant_call_error_error Error + { + readonly get => error; + set => error = value; + } + + public int Argument + { + readonly get => argument; + set => argument = value; + } + + public Godot.Variant.Type Expected + { + readonly get => (Godot.Variant.Type)expected; + set => expected = (int)value; + } } [StructLayout(LayoutKind.Explicit)] // ReSharper disable once InconsistentNaming - public struct godot_variant : IDisposable + public ref struct godot_variant { // Variant.Type is generated as an enum of type long, so we can't use for the field as it must only take 32-bits. [FieldOffset(0)] private int _typeField; // There's padding here - [FieldOffset(8)] internal godot_variant_data _data; - - public Variant.Type _type - { - get => (Variant.Type)_typeField; - set => _typeField = (int)value; - } + [FieldOffset(8)] private godot_variant_data _data; [StructLayout(LayoutKind.Explicit)] // ReSharper disable once InconsistentNaming - internal unsafe struct godot_variant_data + private unsafe ref struct godot_variant_data { [FieldOffset(0)] public godot_bool _bool; [FieldOffset(0)] public long _int; [FieldOffset(0)] public double _float; - [FieldOffset(0)] public Transform2D* _transform2d; + [FieldOffset(0)] public Transform2D* _transform2D; [FieldOffset(0)] public AABB* _aabb; [FieldOffset(0)] public Basis* _basis; - [FieldOffset(0)] public Transform3D* _transform3d; + [FieldOffset(0)] public Transform3D* _transform3D; [FieldOffset(0)] public Vector4* _vector4; [FieldOffset(0)] public Vector4i* _vector4i; [FieldOffset(0)] public Projection* _projection; @@ -125,7 +150,7 @@ namespace Godot.NativeInterop [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - internal struct godot_variant_obj_data + public struct godot_variant_obj_data { public UInt64 id; public IntPtr obj; @@ -133,7 +158,7 @@ namespace Godot.NativeInterop [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - private struct godot_variant_data_mem + public struct godot_variant_data_mem { #pragma warning disable 169 private real_t _mem0; @@ -144,9 +169,225 @@ namespace Godot.NativeInterop } } + public Variant.Type Type + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => (Variant.Type)_typeField; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _typeField = (int)value; + } + + public godot_bool Bool + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._bool; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._bool = value; + } + + public long Int + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._int; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._int = value; + } + + public double Float + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._float; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._float = value; + } + + public readonly unsafe Transform2D* Transform2D + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _data._transform2D; + } + + public readonly unsafe AABB* AABB + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _data._aabb; + } + + public readonly unsafe Basis* Basis + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _data._basis; + } + + public readonly unsafe Transform3D* Transform3D + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _data._transform3D; + } + + public readonly unsafe Vector4* Vector4 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _data._vector4; + } + + public readonly unsafe Vector4i* Vector4i + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _data._vector4i; + } + + public readonly unsafe Projection* Projection + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _data._projection; + } + + public godot_string_name StringName + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_string_name; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_string_name = value; + } + + public godot_string String + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_string; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_string = value; + } + + public Vector3 Vector3 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_vector3; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_vector3 = value; + } + + public Vector3i Vector3i + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_vector3i; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_vector3i = value; + } + + public Vector2 Vector2 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_vector2; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_vector2 = value; + } + + public Vector2i Vector2i + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_vector2i; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_vector2i = value; + } + + public Rect2 Rect2 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_rect2; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_rect2 = value; + } + + public Rect2i Rect2i + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_rect2i; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_rect2i = value; + } + + public Plane Plane + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_plane; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_plane = value; + } + + public Quaternion Quaternion + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_quaternion; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_quaternion = value; + } + + public Color Color + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_color; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_color = value; + } + + public godot_node_path NodePath + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_node_path; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_node_path = value; + } + + public RID RID + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_rid; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_rid = value; + } + + public godot_callable Callable + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_callable; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_callable = value; + } + + public godot_signal Signal + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_signal; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_signal = value; + } + + public godot_dictionary Dictionary + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_dictionary; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_dictionary = value; + } + + public godot_array Array + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + readonly get => _data._m_array; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _data._m_array = value; + } + + public readonly IntPtr Object + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _data._m_obj_data.obj; + } + public void Dispose() { - switch (_type) + switch (Type) { case Variant.Type.Nil: case Variant.Type.Bool: @@ -166,15 +407,36 @@ namespace Godot.NativeInterop } NativeFuncs.godotsharp_variant_destroy(ref this); - _type = Variant.Type.Nil; + Type = Variant.Type.Nil; + } + + [StructLayout(LayoutKind.Explicit)] + // ReSharper disable once InconsistentNaming + internal struct movable + { + // Variant.Type is generated as an enum of type long, so we can't use for the field as it must only take 32-bits. + [FieldOffset(0)] private int _typeField; + + // There's padding here + + [FieldOffset(8)] private godot_variant_data.godot_variant_data_mem _data; + + public static unsafe explicit operator movable(in godot_variant value) + => *(movable*)CustomUnsafe.AsPointer(ref CustomUnsafe.AsRef(value)); + + public static unsafe explicit operator godot_variant(movable value) + => *(godot_variant*)Unsafe.AsPointer(ref value); + + public unsafe ref godot_variant DangerousSelfRef => + ref CustomUnsafe.AsRef((godot_variant*)Unsafe.AsPointer(ref this)); } } [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_string : IDisposable + public ref struct godot_string { - internal IntPtr _ptr; + private IntPtr _ptr; public void Dispose() { @@ -184,15 +446,25 @@ namespace Godot.NativeInterop _ptr = IntPtr.Zero; } + public readonly IntPtr Buffer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr; + } + // Size including the null termination character - public unsafe int Size => _ptr != IntPtr.Zero ? *((int*)_ptr - 1) : 0; + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr != IntPtr.Zero ? *((int*)_ptr - 1) : 0; + } } [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_string_name : IDisposable + public ref struct godot_string_name { - internal IntPtr _data; + private IntPtr _data; public void Dispose() { @@ -202,18 +474,41 @@ namespace Godot.NativeInterop _data = IntPtr.Zero; } - // An static method because an instance method could result in a hidden copy if called on an `in` parameter. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsEmpty(in godot_string_name name) => + public readonly bool IsAllocated + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _data != IntPtr.Zero; + } + + public readonly bool IsEmpty + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] // This is all that's needed to check if it's empty. Equivalent to `== StringName()` in C++. - name._data == IntPtr.Zero; + get => _data == IntPtr.Zero; + } + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct movable + { + private IntPtr _data; + + public static unsafe explicit operator movable(in godot_string_name value) + => *(movable*)CustomUnsafe.AsPointer(ref CustomUnsafe.AsRef(value)); + + public static unsafe explicit operator godot_string_name(movable value) + => *(godot_string_name*)Unsafe.AsPointer(ref value); + + public unsafe ref godot_string_name DangerousSelfRef => + ref CustomUnsafe.AsRef((godot_string_name*)Unsafe.AsPointer(ref this)); + } } [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_node_path : IDisposable + public ref struct godot_node_path { - internal IntPtr _data; + private IntPtr _data; public void Dispose() { @@ -223,49 +518,98 @@ namespace Godot.NativeInterop _data = IntPtr.Zero; } - // An static method because an instance method could result in a hidden copy if called on an `in` parameter. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsEmpty(in godot_node_path nodePath) => + public readonly bool IsAllocated + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _data != IntPtr.Zero; + } + + public readonly bool IsEmpty + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] // This is all that's needed to check if it's empty. It's what the `is_empty()` C++ method does. - nodePath._data == IntPtr.Zero; + get => _data == IntPtr.Zero; + } + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct movable + { + private IntPtr _data; + + public static unsafe explicit operator movable(in godot_node_path value) + => *(movable*)CustomUnsafe.AsPointer(ref CustomUnsafe.AsRef(value)); + + public static unsafe explicit operator godot_node_path(movable value) + => *(godot_node_path*)Unsafe.AsPointer(ref value); + + public unsafe ref godot_node_path DangerousSelfRef => + ref CustomUnsafe.AsRef((godot_node_path*)Unsafe.AsPointer(ref this)); + } } [StructLayout(LayoutKind.Explicit)] // ReSharper disable once InconsistentNaming - public struct godot_signal : IDisposable + public ref struct godot_signal { - [FieldOffset(0)] public godot_string_name _name; + [FieldOffset(0)] private godot_string_name _name; // There's padding here on 32-bit - [FieldOffset(8)] public UInt64 _objectId; + [FieldOffset(8)] private UInt64 _objectId; + + public godot_signal(godot_string_name name, ulong objectId) + { + _name = name; + _objectId = objectId; + } + + public godot_string_name Name + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _name; + } + + public UInt64 ObjectId + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _objectId; + } public void Dispose() { - if (_name._data == IntPtr.Zero) + if (!_name.IsAllocated) return; NativeFuncs.godotsharp_signal_destroy(ref this); - _name._data = IntPtr.Zero; + _name = default; } } [StructLayout(LayoutKind.Explicit)] // ReSharper disable once InconsistentNaming - public struct godot_callable : IDisposable + public ref struct godot_callable { - [FieldOffset(0)] public godot_string_name _method; + [FieldOffset(0)] private godot_string_name _method; // There's padding here on 32-bit - [FieldOffset(8)] public UInt64 _objectId; - [FieldOffset(8)] public IntPtr _custom; + // ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable + [FieldOffset(8)] private UInt64 _objectId; + [FieldOffset(8)] private IntPtr _custom; + + public godot_callable(godot_string_name method, ulong objectId) : this() + { + _method = method; + _objectId = objectId; + } public void Dispose() { - if (_method._data == IntPtr.Zero && _custom == IntPtr.Zero) + // _custom needs freeing as well + if (!_method.IsAllocated && _custom == IntPtr.Zero) return; NativeFuncs.godotsharp_callable_destroy(ref this); - _method._data = IntPtr.Zero; + _method = default; _custom = IntPtr.Zero; } } @@ -275,29 +619,55 @@ namespace Godot.NativeInterop // be re-assigned a new value (the copy constructor checks if `_p` is null so that's fine). [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_array : IDisposable + public ref struct godot_array { - internal unsafe ArrayPrivate* _p; + private unsafe ArrayPrivate* _p; [StructLayout(LayoutKind.Sequential)] - internal struct ArrayPrivate + private struct ArrayPrivate { private uint _safeRefCount; - internal VariantVector _arrayVector; - // There's more here, but we don't care as we never store this in C# + public VariantVector _arrayVector; + // There are more fields here, but we don't care as we never store this in C# + + public readonly int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _arrayVector.Size; + } } [StructLayout(LayoutKind.Sequential)] - internal struct VariantVector + private struct VariantVector { - internal IntPtr _writeProxy; - internal unsafe godot_variant* _ptr; + private IntPtr _writeProxy; + public unsafe godot_variant* _ptr; - public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0; + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr != null ? *((int*)_ptr - 1) : 0; + } + } + + public readonly unsafe godot_variant* Elements + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _p->_arrayVector._ptr; } - public unsafe int Size => _p != null ? _p->_arrayVector.Size : 0; + public readonly unsafe bool IsAllocated + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _p != null; + } + + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _p != null ? _p->Size : 0; + } public unsafe void Dispose() { @@ -306,6 +676,22 @@ namespace Godot.NativeInterop NativeFuncs.godotsharp_array_destroy(ref this); _p = null; } + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct movable + { + private unsafe ArrayPrivate* _p; + + public static unsafe explicit operator movable(in godot_array value) + => *(movable*)CustomUnsafe.AsPointer(ref CustomUnsafe.AsRef(value)); + + public static unsafe explicit operator godot_array(movable value) + => *(godot_array*)Unsafe.AsPointer(ref value); + + public unsafe ref godot_array DangerousSelfRef => + ref CustomUnsafe.AsRef((godot_array*)Unsafe.AsPointer(ref this)); + } } // IMPORTANT: @@ -314,9 +700,15 @@ namespace Godot.NativeInterop // be re-assigned a new value (the copy constructor checks if `_p` is null so that's fine). [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_dictionary : IDisposable + public ref struct godot_dictionary { - internal IntPtr _p; + private IntPtr _p; + + public readonly bool IsAllocated + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _p != IntPtr.Zero; + } public void Dispose() { @@ -325,14 +717,30 @@ namespace Godot.NativeInterop NativeFuncs.godotsharp_dictionary_destroy(ref this); _p = IntPtr.Zero; } + + [StructLayout(LayoutKind.Sequential)] + // ReSharper disable once InconsistentNaming + internal struct movable + { + private IntPtr _p; + + public static unsafe explicit operator movable(in godot_dictionary value) + => *(movable*)CustomUnsafe.AsPointer(ref CustomUnsafe.AsRef(value)); + + public static unsafe explicit operator godot_dictionary(movable value) + => *(godot_dictionary*)Unsafe.AsPointer(ref value); + + public unsafe ref godot_dictionary DangerousSelfRef => + ref CustomUnsafe.AsRef((godot_dictionary*)Unsafe.AsPointer(ref this)); + } } [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_packed_byte_array : IDisposable + public ref struct godot_packed_byte_array { - internal IntPtr _writeProxy; - internal unsafe byte* _ptr; + private IntPtr _writeProxy; + private unsafe byte* _ptr; public unsafe void Dispose() { @@ -342,15 +750,25 @@ namespace Godot.NativeInterop _ptr = null; } - public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0; + public readonly unsafe byte* Buffer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr; + } + + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr != null ? *((int*)_ptr - 1) : 0; + } } [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_packed_int32_array : IDisposable + public ref struct godot_packed_int32_array { - internal IntPtr _writeProxy; - internal unsafe int* _ptr; + private IntPtr _writeProxy; + private unsafe int* _ptr; public unsafe void Dispose() { @@ -360,15 +778,25 @@ namespace Godot.NativeInterop _ptr = null; } - public unsafe int Size => _ptr != null ? *(_ptr - 1) : 0; + public readonly unsafe int* Buffer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr; + } + + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr != null ? *(_ptr - 1) : 0; + } } [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_packed_int64_array : IDisposable + public ref struct godot_packed_int64_array { - internal IntPtr _writeProxy; - internal unsafe long* _ptr; + private IntPtr _writeProxy; + private unsafe long* _ptr; public unsafe void Dispose() { @@ -378,15 +806,25 @@ namespace Godot.NativeInterop _ptr = null; } - public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0; + public readonly unsafe long* Buffer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr; + } + + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr != null ? *((int*)_ptr - 1) : 0; + } } [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_packed_float32_array : IDisposable + public ref struct godot_packed_float32_array { - internal IntPtr _writeProxy; - internal unsafe float* _ptr; + private IntPtr _writeProxy; + private unsafe float* _ptr; public unsafe void Dispose() { @@ -396,15 +834,25 @@ namespace Godot.NativeInterop _ptr = null; } - public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0; + public readonly unsafe float* Buffer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr; + } + + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr != null ? *((int*)_ptr - 1) : 0; + } } [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_packed_float64_array : IDisposable + public ref struct godot_packed_float64_array { - internal IntPtr _writeProxy; - internal unsafe double* _ptr; + private IntPtr _writeProxy; + private unsafe double* _ptr; public unsafe void Dispose() { @@ -414,15 +862,25 @@ namespace Godot.NativeInterop _ptr = null; } - public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0; + public readonly unsafe double* Buffer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr; + } + + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr != null ? *((int*)_ptr - 1) : 0; + } } [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_packed_string_array : IDisposable + public ref struct godot_packed_string_array { - internal IntPtr _writeProxy; - internal unsafe godot_string* _ptr; + private IntPtr _writeProxy; + private unsafe godot_string* _ptr; public unsafe void Dispose() { @@ -432,15 +890,25 @@ namespace Godot.NativeInterop _ptr = null; } - public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0; + public readonly unsafe godot_string* Buffer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr; + } + + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr != null ? *((int*)_ptr - 1) : 0; + } } [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_packed_vector2_array : IDisposable + public ref struct godot_packed_vector2_array { - internal IntPtr _writeProxy; - internal unsafe Vector2* _ptr; + private IntPtr _writeProxy; + private unsafe Vector2* _ptr; public unsafe void Dispose() { @@ -450,15 +918,25 @@ namespace Godot.NativeInterop _ptr = null; } - public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0; + public readonly unsafe Vector2* Buffer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr; + } + + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr != null ? *((int*)_ptr - 1) : 0; + } } [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_packed_vector3_array : IDisposable + public ref struct godot_packed_vector3_array { - internal IntPtr _writeProxy; - internal unsafe Vector3* _ptr; + private IntPtr _writeProxy; + private unsafe Vector3* _ptr; public unsafe void Dispose() { @@ -468,15 +946,25 @@ namespace Godot.NativeInterop _ptr = null; } - public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0; + public readonly unsafe Vector3* Buffer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr; + } + + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr != null ? *((int*)_ptr - 1) : 0; + } } [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming - public struct godot_packed_color_array : IDisposable + public ref struct godot_packed_color_array { - internal IntPtr _writeProxy; - internal unsafe Color* _ptr; + private IntPtr _writeProxy; + private unsafe Color* _ptr; public unsafe void Dispose() { @@ -486,6 +974,16 @@ namespace Godot.NativeInterop _ptr = null; } - public unsafe int Size => _ptr != null ? *((int*)_ptr - 1) : 0; + public readonly unsafe Color* Buffer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr; + } + + public readonly unsafe int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _ptr != null ? *((int*)_ptr - 1) : 0; + } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs index 5779421c69..8ddf28ba16 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Godot.Bridge; @@ -16,22 +15,19 @@ namespace Godot.NativeInterop return null; IntPtr gcHandlePtr; - godot_bool has_cs_script_instance = false.ToGodotBool(); + godot_bool hasCsScriptInstance; // First try to get the tied managed instance from a CSharpInstance script instance - unsafe - { - gcHandlePtr = NativeFuncs.godotsharp_internal_unmanaged_get_script_instance_managed( - unmanaged, &has_cs_script_instance); - } + gcHandlePtr = NativeFuncs.godotsharp_internal_unmanaged_get_script_instance_managed( + unmanaged, out hasCsScriptInstance); if (gcHandlePtr != IntPtr.Zero) return (Object)GCHandle.FromIntPtr(gcHandlePtr).Target; // Otherwise, if the object has a CSharpInstance script instance, return null - if (has_cs_script_instance.ToBool()) + if (hasCsScriptInstance.ToBool()) return null; // If it doesn't have a CSharpInstance script instance, try with native instance bindings @@ -58,12 +54,9 @@ namespace Godot.NativeInterop if (type == nativeType) { - unsafe - { - godot_string_name nativeNameAux = nativeName.NativeValue; - NativeFuncs.godotsharp_internal_tie_native_managed_to_unmanaged( - GCHandle.ToIntPtr(gcHandle), unmanaged, &nativeNameAux, refCounted.ToGodotBool()); - } + var nativeNameSelf = (godot_string_name)nativeName.NativeValue; + NativeFuncs.godotsharp_internal_tie_native_managed_to_unmanaged( + GCHandle.ToIntPtr(gcHandle), unmanaged, nativeNameSelf, refCounted.ToGodotBool()); } else { @@ -88,10 +81,10 @@ namespace Godot.NativeInterop GCHandle.ToIntPtr(strongGCHandle), unmanaged); } - public static unsafe Object EngineGetSingleton(string name) + public static Object EngineGetSingleton(string name) { - using godot_string src = Marshaling.mono_string_to_godot(name); - return UnmanagedGetManaged(NativeFuncs.godotsharp_engine_get_singleton(&src)); + using godot_string src = Marshaling.ConvertStringToNative(name); + return UnmanagedGetManaged(NativeFuncs.godotsharp_engine_get_singleton(src)); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs index 74232425bb..d1a1450f04 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs @@ -1,19 +1,21 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.InteropServices; // ReSharper disable InconsistentNaming +// We want to use full name qualifiers here even if redundant for clarity +// ReSharper disable RedundantNameQualifier + +#nullable enable + namespace Godot.NativeInterop { - // We want to use full name qualifiers here even if redundant for clarity - [SuppressMessage("ReSharper", "RedundantNameQualifier")] public static class Marshaling { - public static Variant.Type managed_to_variant_type(Type type, out bool r_nil_is_variant) + internal static Variant.Type ConvertManagedTypeToVariantType(Type type, out bool r_nil_is_variant) { r_nil_is_variant = false; @@ -106,7 +108,7 @@ namespace Godot.NativeInterop if (type.IsArray || type.IsSZArray) { - if (type == typeof(Byte[])) + if (type == typeof(byte[])) return Variant.Type.PackedByteArray; if (type == typeof(Int32[])) @@ -133,6 +135,15 @@ namespace Godot.NativeInterop if (type == typeof(Color[])) return Variant.Type.PackedColorArray; + if (type == typeof(StringName[])) + return Variant.Type.Array; + + if (type == typeof(NodePath[])) + return Variant.Type.Array; + + if (type == typeof(RID[])) + return Variant.Type.Array; + if (typeof(Godot.Object[]).IsAssignableFrom(type)) return Variant.Type.Array; @@ -161,6 +172,9 @@ namespace Godot.NativeInterop if (genericTypeDefinition == typeof(ICollection<>) || genericTypeDefinition == typeof(IEnumerable<>)) return Variant.Type.Array; + + if (typeof(Godot.Object).IsAssignableFrom(type)) + return Variant.Type.Object; } else if (type == typeof(object)) { @@ -200,44 +214,9 @@ namespace Godot.NativeInterop return Variant.Type.Nil; } - public static bool try_get_array_element_type(Type p_array_type, out Type r_elem_type) - { - if (p_array_type.IsArray || p_array_type.IsSZArray) - { - r_elem_type = p_array_type.GetElementType(); - return true; - } - else if (p_array_type.IsGenericType) - { - var genericTypeDefinition = p_array_type.GetGenericTypeDefinition(); - - if (typeof(Collections.Array) == genericTypeDefinition || - typeof(System.Collections.Generic.List<>) == genericTypeDefinition || - typeof(System.Collections.ICollection) == genericTypeDefinition || - typeof(System.Collections.IEnumerable) == genericTypeDefinition) - { - r_elem_type = p_array_type.GetGenericArguments()[0]; - return true; - } - } - - r_elem_type = null; - return false; - } - /* TODO: Reflection and type checking each time is slow. This will be replaced with source generators. */ - public static godot_variant mono_object_to_variant(object p_obj) - { - return mono_object_to_variant_impl(p_obj); - } - - public static godot_variant mono_object_to_variant_no_err(object p_obj) - { - return mono_object_to_variant_impl(p_obj); - } - - private static unsafe godot_variant mono_object_to_variant_impl(object p_obj, bool p_fail_with_err = true) + public static godot_variant ConvertManagedObjectToVariant(object? p_obj) { if (p_obj == null) return new godot_variant(); @@ -248,7 +227,7 @@ namespace Godot.NativeInterop return VariantUtils.CreateFromBool(@bool); case char @char: return VariantUtils.CreateFromInt(@char); - case SByte @int8: + case sbyte @int8: return VariantUtils.CreateFromInt(@int8); case Int16 @int16: return VariantUtils.CreateFromInt(@int16); @@ -256,7 +235,7 @@ namespace Godot.NativeInterop return VariantUtils.CreateFromInt(@int32); case Int64 @int64: return VariantUtils.CreateFromInt(@int64); - case Byte @uint8: + case byte @uint8: return VariantUtils.CreateFromInt(@uint8); case UInt16 @uint16: return VariantUtils.CreateFromInt(@uint16); @@ -311,58 +290,72 @@ namespace Godot.NativeInterop case string @string: { return VariantUtils.CreateFromStringTakingOwnershipOfDisposableValue( - mono_string_to_godot(@string)); + ConvertStringToNative(@string)); } - case Byte[] byteArray: + case byte[] byteArray: { - using godot_packed_byte_array array = mono_array_to_PackedByteArray(byteArray); - return VariantUtils.CreateFromPackedByteArray(&array); + using godot_packed_byte_array array = ConvertSystemArrayToNativePackedByteArray(byteArray); + return VariantUtils.CreateFromPackedByteArray(array); } case Int32[] int32Array: { - using godot_packed_int32_array array = mono_array_to_PackedInt32Array(int32Array); - return VariantUtils.CreateFromPackedInt32Array(&array); + using godot_packed_int32_array array = ConvertSystemArrayToNativePackedInt32Array(int32Array); + return VariantUtils.CreateFromPackedInt32Array(array); } case Int64[] int64Array: { - using godot_packed_int64_array array = mono_array_to_PackedInt64Array(int64Array); - return VariantUtils.CreateFromPackedInt64Array(&array); + using godot_packed_int64_array array = ConvertSystemArrayToNativePackedInt64Array(int64Array); + return VariantUtils.CreateFromPackedInt64Array(array); } case float[] floatArray: { - using godot_packed_float32_array array = mono_array_to_PackedFloat32Array(floatArray); - return VariantUtils.CreateFromPackedFloat32Array(&array); + using godot_packed_float32_array array = ConvertSystemArrayToNativePackedFloat32Array(floatArray); + return VariantUtils.CreateFromPackedFloat32Array(array); } case double[] doubleArray: { - using godot_packed_float64_array array = mono_array_to_PackedFloat64Array(doubleArray); - return VariantUtils.CreateFromPackedFloat64Array(&array); + using godot_packed_float64_array array = ConvertSystemArrayToNativePackedFloat64Array(doubleArray); + return VariantUtils.CreateFromPackedFloat64Array(array); } case string[] stringArray: { - using godot_packed_string_array array = mono_array_to_PackedStringArray(stringArray); - return VariantUtils.CreateFromPackedStringArray(&array); + using godot_packed_string_array array = ConvertSystemArrayToNativePackedStringArray(stringArray); + return VariantUtils.CreateFromPackedStringArray(array); } case Vector2[] vector2Array: { - using godot_packed_vector2_array array = mono_array_to_PackedVector2Array(vector2Array); - return VariantUtils.CreateFromPackedVector2Array(&array); + using godot_packed_vector2_array array = ConvertSystemArrayToNativePackedVector2Array(vector2Array); + return VariantUtils.CreateFromPackedVector2Array(array); } case Vector3[] vector3Array: { - using godot_packed_vector3_array array = mono_array_to_PackedVector3Array(vector3Array); - return VariantUtils.CreateFromPackedVector3Array(&array); + using godot_packed_vector3_array array = ConvertSystemArrayToNativePackedVector3Array(vector3Array); + return VariantUtils.CreateFromPackedVector3Array(array); } case Color[] colorArray: { - using godot_packed_color_array array = mono_array_to_PackedColorArray(colorArray); - return VariantUtils.CreateFromPackedColorArray(&array); + using godot_packed_color_array array = ConvertSystemArrayToNativePackedColorArray(colorArray); + return VariantUtils.CreateFromPackedColorArray(array); + } + case StringName[] stringNameArray: + { + using godot_array array = ConvertSystemArrayToNativeGodotArray(stringNameArray); + return VariantUtils.CreateFromArray(array); + } + case NodePath[] nodePathArray: + { + using godot_array array = ConvertSystemArrayToNativeGodotArray(nodePathArray); + return VariantUtils.CreateFromArray(array); + } + case RID[] ridArray: + { + using godot_array array = ConvertSystemArrayToNativeGodotArray(ridArray); + return VariantUtils.CreateFromArray(array); } case Godot.Object[] godotObjectArray: { - // ReSharper disable once CoVariantArrayConversion - using godot_array array = mono_array_to_Array(godotObjectArray); - return VariantUtils.CreateFromArray(&array); + using godot_array array = ConvertSystemArrayToNativeGodotArray(godotObjectArray); + return VariantUtils.CreateFromArray(array); } case object[] objectArray: // Last one to avoid catching others like string[] and Godot.Object[] { @@ -370,45 +363,38 @@ namespace Godot.NativeInterop // so we need to check the actual type to make sure it's truly `object[]`. if (objectArray.GetType() == typeof(object[])) { - using godot_array array = mono_array_to_Array(objectArray); - return VariantUtils.CreateFromArray(&array); + using godot_array array = ConvertSystemArrayToNativeGodotArray(objectArray); + return VariantUtils.CreateFromArray(array); } - if (p_fail_with_err) - { - GD.PushError("Attempted to convert a managed array of unmarshallable element type to Variant."); - return new godot_variant(); - } - else - { - return new godot_variant(); - } + GD.PushError("Attempted to convert a managed array of unmarshallable element type to Variant."); + return new godot_variant(); } case Godot.Object godotObject: return VariantUtils.CreateFromGodotObject(godotObject.NativeInstance); case StringName stringName: - return VariantUtils.CreateFromStringName(ref stringName.NativeValue); + return VariantUtils.CreateFromStringName(stringName.NativeValue.DangerousSelfRef); case NodePath nodePath: - return VariantUtils.CreateFromNodePath(ref nodePath.NativeValue); + return VariantUtils.CreateFromNodePath((godot_node_path)nodePath.NativeValue); case RID rid: return VariantUtils.CreateFromRID(rid); case Collections.Dictionary godotDictionary: - return VariantUtils.CreateFromDictionary(godotDictionary.NativeValue); + return VariantUtils.CreateFromDictionary((godot_dictionary)godotDictionary.NativeValue); case Collections.Array godotArray: - return VariantUtils.CreateFromArray(godotArray.NativeValue); + return VariantUtils.CreateFromArray((godot_array)godotArray.NativeValue); case Collections.IGenericGodotDictionary genericGodotDictionary: { var godotDict = genericGodotDictionary.UnderlyingDictionary; if (godotDict == null) return new godot_variant(); - return VariantUtils.CreateFromDictionary(godotDict.NativeValue); + return VariantUtils.CreateFromDictionary((godot_dictionary)godotDict.NativeValue); } case Collections.IGenericGodotArray genericGodotArray: { var godotArray = genericGodotArray.UnderlyingArray; if (godotArray == null) return new godot_variant(); - return VariantUtils.CreateFromArray(godotArray.NativeValue); + return VariantUtils.CreateFromArray((godot_array)godotArray.NativeValue); } default: { @@ -426,14 +412,14 @@ namespace Godot.NativeInterop foreach (KeyValuePair<object, object> entry in (IDictionary)p_obj) godotDict.Add(entry.Key, entry.Value); - return VariantUtils.CreateFromDictionary(godotDict.NativeValue); + return VariantUtils.CreateFromDictionary((godot_dictionary)godotDict.NativeValue); } if (genericTypeDefinition == typeof(System.Collections.Generic.List<>)) { // TODO: Validate element type is compatible with Variant - var nativeGodotArray = mono_array_to_Array((IList)p_obj); - return VariantUtils.CreateFromArray(&nativeGodotArray); + using var nativeGodotArray = ConvertIListToNativeGodotArray((IList)p_obj); + return VariantUtils.CreateFromArray(nativeGodotArray); } } @@ -441,38 +427,31 @@ namespace Godot.NativeInterop } } - if (p_fail_with_err) - { - GD.PushError("Attempted to convert an unmarshallable managed type to Variant. Name: '" + - p_obj.GetType().FullName + "."); - return new godot_variant(); - } - else - { - return new godot_variant(); - } + GD.PushError("Attempted to convert an unmarshallable managed type to Variant. Name: '" + + p_obj.GetType().FullName + "."); + return new godot_variant(); } - public static unsafe string variant_to_mono_string(godot_variant* p_var) + private static string? ConvertVariantToManagedString(in godot_variant p_var) { - switch ((*p_var)._type) + switch (p_var.Type) { case Variant.Type.Nil: return null; // Otherwise, Variant -> String would return the string "Null" case Variant.Type.String: { // We avoid the internal call if the stored type is the same we want. - return mono_string_from_godot((*p_var)._data._m_string); + return ConvertStringToManaged(p_var.String); } default: { using godot_string godotString = NativeFuncs.godotsharp_variant_as_string(p_var); - return mono_string_from_godot(godotString); + return ConvertStringToManaged(godotString); } } } - public static unsafe object variant_to_mono_object_of_type(godot_variant* p_var, Type type) + public static object? ConvertVariantToManagedObjectOfType(in godot_variant p_var, Type type) { // This function is only needed to set the value of properties. Fields have their own implementation, set_value_from_variant. switch (Type.GetTypeCode(type)) @@ -502,7 +481,7 @@ namespace Godot.NativeInterop case TypeCode.Double: return VariantUtils.ConvertToFloat64(p_var); case TypeCode.String: - return variant_to_mono_string(p_var); + return ConvertVariantToManagedString(p_var); default: { if (type == typeof(Vector2)) @@ -556,13 +535,13 @@ namespace Godot.NativeInterop if (type == typeof(Callable)) { using godot_callable callable = NativeFuncs.godotsharp_variant_as_callable(p_var); - return ConvertCallableToManaged(&callable); + return ConvertCallableToManaged(in callable); } if (type == typeof(SignalInfo)) { using godot_signal signal = NativeFuncs.godotsharp_variant_as_signal(p_var); - return ConvertSignalToManaged(&signal); + return ConvertSignalToManaged(in signal); } if (type.IsEnum) @@ -597,12 +576,12 @@ namespace Godot.NativeInterop } if (type.IsArray || type.IsSZArray) - return variant_to_mono_array_of_type(p_var, type); + return ConvertVariantToSystemArrayOfType(p_var, type); else if (type.IsGenericType) - return variant_to_mono_object_of_genericinst(p_var, type); + return ConvertVariantToManagedObjectOfGenericType(p_var, type); else if (type == typeof(object)) - return variant_to_mono_object(p_var); - if (variant_to_mono_object_of_class(p_var, type, out object res)) + return ConvertVariantToManagedObject(p_var); + if (ConvertVariantToManagedObjectOfClass(p_var, type, out object? res)) return res; break; @@ -614,72 +593,90 @@ namespace Godot.NativeInterop return null; } - private static unsafe object variant_to_mono_array_of_type(godot_variant* p_var, Type type) + private static object? ConvertVariantToSystemArrayOfType(in godot_variant p_var, Type type) { - if (type == typeof(Byte[])) + if (type == typeof(byte[])) { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_byte_array(p_var); - return PackedByteArray_to_mono_array(&packedArray); + return ConvertNativePackedByteArrayToSystemArray(packedArray); } if (type == typeof(Int32[])) { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_int32_array(p_var); - return PackedInt32Array_to_mono_array(&packedArray); + return ConvertNativePackedInt32ArrayToSystemArray(packedArray); } if (type == typeof(Int64[])) { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_int64_array(p_var); - return PackedInt64Array_to_mono_array(&packedArray); + return ConvertNativePackedInt64ArrayToSystemArray(packedArray); } if (type == typeof(float[])) { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_float32_array(p_var); - return PackedFloat32Array_to_mono_array(&packedArray); + return ConvertNativePackedFloat32ArrayToSystemArray(packedArray); } if (type == typeof(double[])) { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_float64_array(p_var); - return PackedFloat64Array_to_mono_array(&packedArray); + return ConvertNativePackedFloat64ArrayToSystemArray(packedArray); } if (type == typeof(string[])) { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_string_array(p_var); - return PackedStringArray_to_mono_array(&packedArray); + return ConvertNativePackedStringArrayToSystemArray(packedArray); } if (type == typeof(Vector2[])) { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector2_array(p_var); - return PackedVector2Array_to_mono_array(&packedArray); + return ConvertNativePackedVector2ArrayToSystemArray(packedArray); } if (type == typeof(Vector3[])) { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector3_array(p_var); - return PackedVector3Array_to_mono_array(&packedArray); + return ConvertNativePackedVector3ArrayToSystemArray(packedArray); } if (type == typeof(Color[])) { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_color_array(p_var); - return PackedColorArray_to_mono_array(&packedArray); + return ConvertNativePackedColorArrayToSystemArray(packedArray); + } + + if (type == typeof(StringName[])) + { + using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); + return ConvertNativeGodotArrayToSystemArrayOfType(godotArray, type); + } + + if (type == typeof(NodePath[])) + { + using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); + return ConvertNativeGodotArrayToSystemArrayOfType(godotArray, type); + } + + if (type == typeof(RID[])) + { + using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); + return ConvertNativeGodotArrayToSystemArrayOfType(godotArray, type); } if (typeof(Godot.Object[]).IsAssignableFrom(type)) { using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); - return Array_to_mono_array_of_godot_object_type(&godotArray, type); + return ConvertNativeGodotArrayToSystemArrayOfType(godotArray, type); } if (type == typeof(object[])) { using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); - return Array_to_mono_array(&godotArray); + return ConvertNativeGodotArrayToSystemArray(godotArray); } GD.PushError("Attempted to convert Variant to array of unsupported element type. Name: " + @@ -687,7 +684,8 @@ namespace Godot.NativeInterop return null; } - private static unsafe bool variant_to_mono_object_of_class(godot_variant* p_var, Type type, out object res) + private static bool ConvertVariantToManagedObjectOfClass(in godot_variant p_var, Type type, + out object? res) { if (typeof(Godot.Object).IsAssignableFrom(type)) { @@ -735,33 +733,33 @@ namespace Godot.NativeInterop return false; } - private static unsafe object variant_to_mono_object_of_genericinst(godot_variant* p_var, Type type) + private static object? ConvertVariantToManagedObjectOfGenericType(in godot_variant p_var, Type type) { - static object variant_to_generic_godot_collections_dictionary(godot_variant* p_var, Type fullType) + static object ConvertVariantToGenericGodotCollectionsDictionary(in godot_variant p_var, Type fullType) { var underlyingDict = Collections.Dictionary.CreateTakingOwnershipOfDisposableValue( VariantUtils.ConvertToDictionary(p_var)); return Activator.CreateInstance(fullType, BindingFlags.Public | BindingFlags.Instance, null, - args: new object[] { underlyingDict }, null); + args: new object[] { underlyingDict }, null)!; } - static object variant_to_generic_godot_collections_array(godot_variant* p_var, Type fullType) + static object ConvertVariantToGenericGodotCollectionsArray(in godot_variant p_var, Type fullType) { var underlyingArray = Collections.Array.CreateTakingOwnershipOfDisposableValue( VariantUtils.ConvertToArray(p_var)); return Activator.CreateInstance(fullType, BindingFlags.Public | BindingFlags.Instance, null, - args: new object[] { underlyingArray }, null); + args: new object[] { underlyingArray }, null)!; } var genericTypeDefinition = type.GetGenericTypeDefinition(); if (genericTypeDefinition == typeof(Collections.Dictionary<,>)) - return variant_to_generic_godot_collections_dictionary(p_var, type); + return ConvertVariantToGenericGodotCollectionsDictionary(p_var, type); if (genericTypeDefinition == typeof(Collections.Array<>)) - return variant_to_generic_godot_collections_array(p_var, type); + return ConvertVariantToGenericGodotCollectionsArray(p_var, type); if (genericTypeDefinition == typeof(System.Collections.Generic.Dictionary<,>)) { @@ -773,7 +771,7 @@ namespace Godot.NativeInterop args: new object[] { /* capacity: */ godotDictionary.Count - }, null); + }, null)!; foreach (System.Collections.DictionaryEntry pair in godotDictionary) dictionary.Add(pair.Key, pair.Value); @@ -791,7 +789,7 @@ namespace Godot.NativeInterop args: new object[] { /* capacity: */ godotArray.Count - }, null); + }, null)!; foreach (object elem in godotArray) list.Add(elem); @@ -807,7 +805,7 @@ namespace Godot.NativeInterop var genericGodotDictionaryType = typeof(Collections.Dictionary<,>) .MakeGenericType(keyType, valueType); - return variant_to_generic_godot_collections_dictionary(p_var, genericGodotDictionaryType); + return ConvertVariantToGenericGodotCollectionsDictionary(p_var, genericGodotDictionaryType); } if (genericTypeDefinition == typeof(ICollection<>) || genericTypeDefinition == typeof(IEnumerable<>)) @@ -816,138 +814,141 @@ namespace Godot.NativeInterop var genericGodotArrayType = typeof(Collections.Array<>) .MakeGenericType(elementType); - return variant_to_generic_godot_collections_array(p_var, genericGodotArrayType); + return ConvertVariantToGenericGodotCollectionsArray(p_var, genericGodotArrayType); } + if (typeof(Godot.Object).IsAssignableFrom(type)) + return InteropUtils.UnmanagedGetManaged(VariantUtils.ConvertToGodotObject(p_var)); + return null; } - public static unsafe object variant_to_mono_object(godot_variant* p_var) + public static unsafe object? ConvertVariantToManagedObject(in godot_variant p_var) { - switch ((*p_var)._type) + switch (p_var.Type) { case Variant.Type.Bool: - return (*p_var)._data._bool.ToBool(); + return p_var.Bool.ToBool(); case Variant.Type.Int: - return (*p_var)._data._int; + return p_var.Int; case Variant.Type.Float: { #if REAL_T_IS_DOUBLE - return (*p_var)._data._float; + return p_var.Float; #else - return (float)(*p_var)._data._float; + return (float)p_var.Float; #endif } case Variant.Type.String: - return mono_string_from_godot((*p_var)._data._m_string); + return ConvertStringToManaged(p_var.String); case Variant.Type.Vector2: - return (*p_var)._data._m_vector2; + return p_var.Vector2; case Variant.Type.Vector2i: - return (*p_var)._data._m_vector2i; + return p_var.Vector2i; case Variant.Type.Rect2: - return (*p_var)._data._m_rect2; + return p_var.Rect2; case Variant.Type.Rect2i: - return (*p_var)._data._m_rect2i; + return p_var.Rect2i; case Variant.Type.Vector3: - return (*p_var)._data._m_vector3; + return p_var.Vector3; case Variant.Type.Vector3i: - return (*p_var)._data._m_vector3i; + return p_var.Vector3i; case Variant.Type.Transform2d: - return *(*p_var)._data._transform2d; + return *p_var.Transform2D; case Variant.Type.Vector4: - return *(*p_var)._data._vector4; + return *p_var.Vector4; case Variant.Type.Vector4i: - return *(*p_var)._data._vector4i; + return *p_var.Vector4i; case Variant.Type.Plane: - return (*p_var)._data._m_plane; + return p_var.Plane; case Variant.Type.Quaternion: - return (*p_var)._data._m_quaternion; + return p_var.Quaternion; case Variant.Type.Aabb: - return *(*p_var)._data._aabb; + return *p_var.AABB; case Variant.Type.Basis: - return *(*p_var)._data._basis; + return *p_var.Basis; case Variant.Type.Transform3d: - return *(*p_var)._data._transform3d; + return *p_var.Transform3D; case Variant.Type.Projection: - return *(*p_var)._data._projection; + return *p_var.Projection; case Variant.Type.Color: - return (*p_var)._data._m_color; + return p_var.Color; case Variant.Type.StringName: { // The Variant owns the value, so we need to make a copy return StringName.CreateTakingOwnershipOfDisposableValue( - NativeFuncs.godotsharp_string_name_new_copy(&(*p_var)._data._m_string_name)); + NativeFuncs.godotsharp_string_name_new_copy(p_var.StringName)); } case Variant.Type.NodePath: { // The Variant owns the value, so we need to make a copy return NodePath.CreateTakingOwnershipOfDisposableValue( - NativeFuncs.godotsharp_node_path_new_copy(&(*p_var)._data._m_node_path)); + NativeFuncs.godotsharp_node_path_new_copy(p_var.NodePath)); } case Variant.Type.Rid: - return (*p_var)._data._m_rid; + return p_var.RID; case Variant.Type.Object: - return InteropUtils.UnmanagedGetManaged((*p_var)._data._m_obj_data.obj); + return InteropUtils.UnmanagedGetManaged(p_var.Object); case Variant.Type.Callable: - return ConvertCallableToManaged(&(*p_var)._data._m_callable); + return ConvertCallableToManaged(p_var.Callable); case Variant.Type.Signal: - return ConvertSignalToManaged(&(*p_var)._data._m_signal); + return ConvertSignalToManaged(p_var.Signal); case Variant.Type.Dictionary: { // The Variant owns the value, so we need to make a copy return Collections.Dictionary.CreateTakingOwnershipOfDisposableValue( - NativeFuncs.godotsharp_dictionary_new_copy(&(*p_var)._data._m_dictionary)); + NativeFuncs.godotsharp_dictionary_new_copy(p_var.Dictionary)); } case Variant.Type.Array: { // The Variant owns the value, so we need to make a copy return Collections.Array.CreateTakingOwnershipOfDisposableValue( - NativeFuncs.godotsharp_array_new_copy(&(*p_var)._data._m_array)); + NativeFuncs.godotsharp_array_new_copy(p_var.Array)); } case Variant.Type.PackedByteArray: { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_byte_array(p_var); - return PackedByteArray_to_mono_array(&packedArray); + return ConvertNativePackedByteArrayToSystemArray(packedArray); } case Variant.Type.PackedInt32Array: { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_int32_array(p_var); - return PackedInt32Array_to_mono_array(&packedArray); + return ConvertNativePackedInt32ArrayToSystemArray(packedArray); } case Variant.Type.PackedInt64Array: { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_int64_array(p_var); - return PackedInt64Array_to_mono_array(&packedArray); + return ConvertNativePackedInt64ArrayToSystemArray(packedArray); } case Variant.Type.PackedFloat32Array: { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_float32_array(p_var); - return PackedFloat32Array_to_mono_array(&packedArray); + return ConvertNativePackedFloat32ArrayToSystemArray(packedArray); } case Variant.Type.PackedFloat64Array: { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_float64_array(p_var); - return PackedFloat64Array_to_mono_array(&packedArray); + return ConvertNativePackedFloat64ArrayToSystemArray(packedArray); } case Variant.Type.PackedStringArray: { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_string_array(p_var); - return PackedStringArray_to_mono_array(&packedArray); + return ConvertNativePackedStringArrayToSystemArray(packedArray); } case Variant.Type.PackedVector2Array: { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector2_array(p_var); - return PackedVector2Array_to_mono_array(&packedArray); + return ConvertNativePackedVector2ArrayToSystemArray(packedArray); } case Variant.Type.PackedVector3Array: { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector3_array(p_var); - return PackedVector3Array_to_mono_array(&packedArray); + return ConvertNativePackedVector3ArrayToSystemArray(packedArray); } case Variant.Type.PackedColorArray: { using var packedArray = NativeFuncs.godotsharp_variant_as_packed_color_array(p_var); - return PackedColorArray_to_mono_array(&packedArray); + return ConvertNativePackedColorArrayToSystemArray(packedArray); } default: return null; @@ -956,26 +957,25 @@ namespace Godot.NativeInterop // String - public static unsafe godot_string mono_string_to_godot(string p_mono_string) + public static unsafe godot_string ConvertStringToNative(string? p_mono_string) { if (p_mono_string == null) return new godot_string(); fixed (char* methodChars = p_mono_string) { - godot_string dest; - NativeFuncs.godotsharp_string_new_with_utf16_chars(&dest, methodChars); + NativeFuncs.godotsharp_string_new_with_utf16_chars(out godot_string dest, methodChars); return dest; } } - public static unsafe string mono_string_from_godot(in godot_string p_string) + public static unsafe string ConvertStringToManaged(in godot_string p_string) { - if (p_string._ptr == IntPtr.Zero) + if (p_string.Buffer == IntPtr.Zero) return string.Empty; const int sizeOfChar32 = 4; - byte* bytes = (byte*)p_string._ptr; + byte* bytes = (byte*)p_string.Buffer; int size = p_string.Size; if (size == 0) return string.Empty; @@ -987,54 +987,45 @@ namespace Godot.NativeInterop // Callable public static godot_callable ConvertCallableToNative(ref Callable p_managed_callable) + => ConvertCallableToNative(p_managed_callable); + + public static godot_callable ConvertCallableToNative(Callable p_managed_callable) { if (p_managed_callable.Delegate != null) { - unsafe - { - godot_callable callable; - NativeFuncs.godotsharp_callable_new_with_delegate( - GCHandle.ToIntPtr(GCHandle.Alloc(p_managed_callable.Delegate)), &callable); - return callable; - } + NativeFuncs.godotsharp_callable_new_with_delegate( + GCHandle.ToIntPtr(GCHandle.Alloc(p_managed_callable.Delegate)), + out godot_callable callable); + return callable; } else { - unsafe - { - godot_string_name method; - - if (p_managed_callable.Method != null && !p_managed_callable.Method.IsEmpty) - { - godot_string_name src = p_managed_callable.Method.NativeValue; - method = NativeFuncs.godotsharp_string_name_new_copy(&src); - } - else - { - method = default; - } + godot_string_name method; - return new godot_callable - { - _method = method, // Takes ownership of disposable - _objectId = p_managed_callable.Target.GetInstanceId() - }; + if (p_managed_callable.Method != null && !p_managed_callable.Method.IsEmpty) + { + var src = (godot_string_name)p_managed_callable.Method.NativeValue; + method = NativeFuncs.godotsharp_string_name_new_copy(src); } + else + { + method = default; + } + + return new godot_callable(method /* Takes ownership of disposable */, + p_managed_callable.Target.GetInstanceId()); } } - public static unsafe Callable ConvertCallableToManaged(godot_callable* p_callable) + public static Callable ConvertCallableToManaged(in godot_callable p_callable) { - IntPtr delegateGCHandle; - IntPtr godotObject; - godot_string_name name; - - if (NativeFuncs.godotsharp_callable_get_data_for_marshalling( - p_callable, &delegateGCHandle, &godotObject, &name).ToBool()) + if (NativeFuncs.godotsharp_callable_get_data_for_marshalling(p_callable, + out IntPtr delegateGCHandle, out IntPtr godotObject, + out godot_string_name name).ToBool()) { if (delegateGCHandle != IntPtr.Zero) { - return new Callable((Delegate)GCHandle.FromIntPtr(delegateGCHandle).Target); + return new Callable((Delegate?)GCHandle.FromIntPtr(delegateGCHandle).Target); } else { @@ -1053,39 +1044,32 @@ namespace Godot.NativeInterop public static godot_signal ConvertSignalToNative(ref SignalInfo p_managed_signal) { ulong ownerId = p_managed_signal.Owner.GetInstanceId(); - unsafe - { - godot_string_name name; - - if (p_managed_signal.Name != null && !p_managed_signal.Name.IsEmpty) - { - godot_string_name src = p_managed_signal.Name.NativeValue; - name = NativeFuncs.godotsharp_string_name_new_copy(&src); - } - else - { - name = default; - } + godot_string_name name; - return new godot_signal() - { - _name = name, - _objectId = ownerId - }; + if (p_managed_signal.Name != null && !p_managed_signal.Name.IsEmpty) + { + var src = (godot_string_name)p_managed_signal.Name.NativeValue; + name = NativeFuncs.godotsharp_string_name_new_copy(src); } + else + { + name = default; + } + + return new godot_signal(name, ownerId); } - public static unsafe SignalInfo ConvertSignalToManaged(godot_signal* p_signal) + public static SignalInfo ConvertSignalToManaged(in godot_signal p_signal) { - var owner = GD.InstanceFromId((*p_signal)._objectId); + var owner = GD.InstanceFromId(p_signal.ObjectId); var name = StringName.CreateTakingOwnershipOfDisposableValue( - NativeFuncs.godotsharp_string_name_new_copy(&(*p_signal)._name)); + NativeFuncs.godotsharp_string_name_new_copy(p_signal.Name)); return new SignalInfo(owner, name); } // Array - public static unsafe object[] Array_to_mono_array(godot_array* p_array) + public static object[] ConvertNativeGodotArrayToSystemArray(in godot_array p_array) { var array = Collections.Array.CreateTakingOwnershipOfDisposableValue( NativeFuncs.godotsharp_array_new_copy(p_array)); @@ -1093,27 +1077,27 @@ namespace Godot.NativeInterop int length = array.Count; var ret = new object[length]; - array.CopyTo(ret, 0); // variant_to_mono_object handled by Collections.Array + array.CopyTo(ret, 0); // ConvertVariantToManagedObject handled by Collections.Array return ret; } - public static unsafe object Array_to_mono_array_of_godot_object_type(godot_array* p_array, Type type) + private static object ConvertNativeGodotArrayToSystemArrayOfType(in godot_array p_array, Type type) { var array = Collections.Array.CreateTakingOwnershipOfDisposableValue( NativeFuncs.godotsharp_array_new_copy(p_array)); int length = array.Count; - object ret = Activator.CreateInstance(type, length); + object ret = Activator.CreateInstance(type, length)!; - // variant_to_mono_object handled by Collections.Array - // variant_to_mono_object_of_type is not needed because target element types are Godot.Object (or derived) + // ConvertVariantToManagedObject handled by Collections.Array + // ConvertVariantToManagedObjectOfType is not needed because target element types are Godot.Object (or derived) array.CopyTo((object[])ret, 0); return ret; } - public static godot_array mono_array_to_Array(object[] p_array) + public static godot_array ConvertSystemArrayToNativeGodotArray(object[] p_array) { int length = p_array.Length; @@ -1126,14 +1110,28 @@ namespace Godot.NativeInterop for (int i = 0; i < length; i++) array[i] = p_array[i]; - godot_array src = array.NativeValue; - unsafe - { - return NativeFuncs.godotsharp_array_new_copy(&src); - } + var src = (godot_array)array.NativeValue; + return NativeFuncs.godotsharp_array_new_copy(src); + } + + public static godot_array ConvertSystemArrayToNativeGodotArray<T>(T[] p_array) + { + int length = p_array.Length; + + if (length == 0) + return NativeFuncs.godotsharp_array_new(); + + using var array = new Collections.Array(); + array.Resize(length); + + for (int i = 0; i < length; i++) + array[i] = p_array[i]; + + var src = (godot_array)array.NativeValue; + return NativeFuncs.godotsharp_array_new_copy(src); } - public static godot_array mono_array_to_Array(IList p_array) + public static godot_array ConvertIListToNativeGodotArray(IList p_array) { int length = p_array.Count; @@ -1146,26 +1144,25 @@ namespace Godot.NativeInterop for (int i = 0; i < length; i++) array[i] = p_array[i]; - godot_array src = array.NativeValue; - unsafe - { - return NativeFuncs.godotsharp_array_new_copy(&src); - } + var src = (godot_array)array.NativeValue; + return NativeFuncs.godotsharp_array_new_copy(src); } // PackedByteArray - public static unsafe byte[] PackedByteArray_to_mono_array(godot_packed_byte_array* p_array) + public static unsafe byte[] ConvertNativePackedByteArrayToSystemArray(in godot_packed_byte_array p_array) { - byte* buffer = (*p_array)._ptr; - int size = (*p_array).Size; + byte* buffer = p_array.Buffer; + int size = p_array.Size; + if (size == 0) + return Array.Empty<byte>(); var array = new byte[size]; fixed (byte* dest = array) Buffer.MemoryCopy(buffer, dest, size, size); return array; } - public static unsafe godot_packed_byte_array mono_array_to_PackedByteArray(Span<byte> p_array) + public static unsafe godot_packed_byte_array ConvertSystemArrayToNativePackedByteArray(Span<byte> p_array) { if (p_array.IsEmpty) return new godot_packed_byte_array(); @@ -1175,10 +1172,12 @@ namespace Godot.NativeInterop // PackedInt32Array - public static unsafe int[] PackedInt32Array_to_mono_array(godot_packed_int32_array* p_array) + public static unsafe int[] ConvertNativePackedInt32ArrayToSystemArray(godot_packed_int32_array p_array) { - int* buffer = (*p_array)._ptr; - int size = (*p_array).Size; + int* buffer = p_array.Buffer; + int size = p_array.Size; + if (size == 0) + return Array.Empty<int>(); int sizeInBytes = size * sizeof(int); var array = new int[size]; fixed (int* dest = array) @@ -1186,7 +1185,7 @@ namespace Godot.NativeInterop return array; } - public static unsafe godot_packed_int32_array mono_array_to_PackedInt32Array(Span<int> p_array) + public static unsafe godot_packed_int32_array ConvertSystemArrayToNativePackedInt32Array(Span<int> p_array) { if (p_array.IsEmpty) return new godot_packed_int32_array(); @@ -1196,10 +1195,12 @@ namespace Godot.NativeInterop // PackedInt64Array - public static unsafe long[] PackedInt64Array_to_mono_array(godot_packed_int64_array* p_array) + public static unsafe long[] ConvertNativePackedInt64ArrayToSystemArray(godot_packed_int64_array p_array) { - long* buffer = (*p_array)._ptr; - int size = (*p_array).Size; + long* buffer = p_array.Buffer; + int size = p_array.Size; + if (size == 0) + return Array.Empty<long>(); int sizeInBytes = size * sizeof(long); var array = new long[size]; fixed (long* dest = array) @@ -1207,7 +1208,7 @@ namespace Godot.NativeInterop return array; } - public static unsafe godot_packed_int64_array mono_array_to_PackedInt64Array(Span<long> p_array) + public static unsafe godot_packed_int64_array ConvertSystemArrayToNativePackedInt64Array(Span<long> p_array) { if (p_array.IsEmpty) return new godot_packed_int64_array(); @@ -1217,10 +1218,12 @@ namespace Godot.NativeInterop // PackedFloat32Array - public static unsafe float[] PackedFloat32Array_to_mono_array(godot_packed_float32_array* p_array) + public static unsafe float[] ConvertNativePackedFloat32ArrayToSystemArray(godot_packed_float32_array p_array) { - float* buffer = (*p_array)._ptr; - int size = (*p_array).Size; + float* buffer = p_array.Buffer; + int size = p_array.Size; + if (size == 0) + return Array.Empty<float>(); int sizeInBytes = size * sizeof(float); var array = new float[size]; fixed (float* dest = array) @@ -1228,7 +1231,8 @@ namespace Godot.NativeInterop return array; } - public static unsafe godot_packed_float32_array mono_array_to_PackedFloat32Array(Span<float> p_array) + public static unsafe godot_packed_float32_array ConvertSystemArrayToNativePackedFloat32Array( + Span<float> p_array) { if (p_array.IsEmpty) return new godot_packed_float32_array(); @@ -1238,10 +1242,12 @@ namespace Godot.NativeInterop // PackedFloat64Array - public static unsafe double[] PackedFloat64Array_to_mono_array(godot_packed_float64_array* p_array) + public static unsafe double[] ConvertNativePackedFloat64ArrayToSystemArray(godot_packed_float64_array p_array) { - double* buffer = (*p_array)._ptr; - int size = (*p_array).Size; + double* buffer = p_array.Buffer; + int size = p_array.Size; + if (size == 0) + return Array.Empty<double>(); int sizeInBytes = size * sizeof(double); var array = new double[size]; fixed (double* dest = array) @@ -1249,7 +1255,8 @@ namespace Godot.NativeInterop return array; } - public static unsafe godot_packed_float64_array mono_array_to_PackedFloat64Array(Span<double> p_array) + public static unsafe godot_packed_float64_array ConvertSystemArrayToNativePackedFloat64Array( + Span<double> p_array) { if (p_array.IsEmpty) return new godot_packed_float64_array(); @@ -1259,19 +1266,19 @@ namespace Godot.NativeInterop // PackedStringArray - public static unsafe string[] PackedStringArray_to_mono_array(godot_packed_string_array* p_array) + public static unsafe string[] ConvertNativePackedStringArrayToSystemArray(godot_packed_string_array p_array) { - godot_string* buffer = (*p_array)._ptr; - if (buffer == null) - return new string[] { }; - int size = (*p_array).Size; + godot_string* buffer = p_array.Buffer; + int size = p_array.Size; + if (size == 0) + return Array.Empty<string>(); var array = new string[size]; for (int i = 0; i < size; i++) - array[i] = mono_string_from_godot(buffer[i]); + array[i] = ConvertStringToManaged(buffer[i]); return array; } - public static unsafe godot_packed_string_array mono_array_to_PackedStringArray(Span<string> p_array) + public static godot_packed_string_array ConvertSystemArrayToNativePackedStringArray(Span<string> p_array) { godot_packed_string_array dest = new godot_packed_string_array(); @@ -1283,8 +1290,8 @@ namespace Godot.NativeInterop for (int i = 0; i < p_array.Length; i++) { - using godot_string godotStrElem = mono_string_to_godot(p_array[i]); - NativeFuncs.godotsharp_packed_string_array_add(&dest, &godotStrElem); + using godot_string godotStrElem = ConvertStringToNative(p_array[i]); + NativeFuncs.godotsharp_packed_string_array_add(ref dest, godotStrElem); } return dest; @@ -1292,10 +1299,12 @@ namespace Godot.NativeInterop // PackedVector2Array - public static unsafe Vector2[] PackedVector2Array_to_mono_array(godot_packed_vector2_array* p_array) + public static unsafe Vector2[] ConvertNativePackedVector2ArrayToSystemArray(godot_packed_vector2_array p_array) { - Vector2* buffer = (*p_array)._ptr; - int size = (*p_array).Size; + Vector2* buffer = p_array.Buffer; + int size = p_array.Size; + if (size == 0) + return Array.Empty<Vector2>(); int sizeInBytes = size * sizeof(Vector2); var array = new Vector2[size]; fixed (Vector2* dest = array) @@ -1303,7 +1312,8 @@ namespace Godot.NativeInterop return array; } - public static unsafe godot_packed_vector2_array mono_array_to_PackedVector2Array(Span<Vector2> p_array) + public static unsafe godot_packed_vector2_array ConvertSystemArrayToNativePackedVector2Array( + Span<Vector2> p_array) { if (p_array.IsEmpty) return new godot_packed_vector2_array(); @@ -1313,10 +1323,12 @@ namespace Godot.NativeInterop // PackedVector3Array - public static unsafe Vector3[] PackedVector3Array_to_mono_array(godot_packed_vector3_array* p_array) + public static unsafe Vector3[] ConvertNativePackedVector3ArrayToSystemArray(godot_packed_vector3_array p_array) { - Vector3* buffer = (*p_array)._ptr; - int size = (*p_array).Size; + Vector3* buffer = p_array.Buffer; + int size = p_array.Size; + if (size == 0) + return Array.Empty<Vector3>(); int sizeInBytes = size * sizeof(Vector3); var array = new Vector3[size]; fixed (Vector3* dest = array) @@ -1324,7 +1336,8 @@ namespace Godot.NativeInterop return array; } - public static unsafe godot_packed_vector3_array mono_array_to_PackedVector3Array(Span<Vector3> p_array) + public static unsafe godot_packed_vector3_array ConvertSystemArrayToNativePackedVector3Array( + Span<Vector3> p_array) { if (p_array.IsEmpty) return new godot_packed_vector3_array(); @@ -1334,10 +1347,12 @@ namespace Godot.NativeInterop // PackedColorArray - public static unsafe Color[] PackedColorArray_to_mono_array(godot_packed_color_array* p_array) + public static unsafe Color[] ConvertNativePackedColorArrayToSystemArray(godot_packed_color_array p_array) { - Color* buffer = (*p_array)._ptr; - int size = (*p_array).Size; + Color* buffer = p_array.Buffer; + int size = p_array.Size; + if (size == 0) + return Array.Empty<Color>(); int sizeInBytes = size * sizeof(Color); var array = new Color[size]; fixed (Color* dest = array) @@ -1345,7 +1360,7 @@ namespace Godot.NativeInterop return array; } - public static unsafe godot_packed_color_array mono_array_to_PackedColorArray(Span<Color> p_array) + public static unsafe godot_packed_color_array ConvertSystemArrayToNativePackedColorArray(Span<Color> p_array) { if (p_array.IsEmpty) return new godot_packed_color_array(); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs index 8bc785f375..f1cccfed0a 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs @@ -1,15 +1,23 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; // ReSharper disable InconsistentNaming namespace Godot.NativeInterop { -#if !NET - // This improves P/Invoke performance. - // The attribute is not available with .NET Core and it's not needed there. - [System.Security.SuppressUnmanagedCodeSecurity] -#endif + /* + * TODO: + * P/Invoke pins by-ref parameters in case the managed memory is moved. + * That's not needed here since we use "ref structs" which are stack-only. + * Unfortunately, the runtime is not smart enough and pins them anyway. + * We want to avoid pinning, so we must wrap these DllImports in methods + * that reinterpret refs and pointers with CustomUnsafe.AsPointer/AsRef. + * I wish such unnecessary boilerplate wasn't needed... + */ + + [SuppressMessage("Interoperability", "CA1401", + MessageId = "P/Invokes should not be visible" /* Meh. What are you gonna do about it? */)] public static unsafe partial class NativeFuncs { private const string GodotDllName = "__Internal"; @@ -17,15 +25,15 @@ namespace Godot.NativeInterop // Custom functions [DllImport(GodotDllName)] - public static extern IntPtr godotsharp_method_bind_get_method(ref godot_string_name p_classname, + public static extern IntPtr godotsharp_method_bind_get_method(in godot_string_name p_classname, char* p_methodname); [DllImport(GodotDllName)] public static extern delegate* unmanaged<IntPtr> godotsharp_get_class_constructor( - ref godot_string_name p_classname); + in godot_string_name p_classname); [DllImport(GodotDllName)] - public static extern IntPtr godotsharp_engine_get_singleton(godot_string* p_name); + public static extern IntPtr godotsharp_engine_get_singleton(in godot_string p_name); [DllImport(GodotDllName)] internal static extern void godotsharp_internal_object_disposed(IntPtr ptr); @@ -35,61 +43,64 @@ namespace Godot.NativeInterop [DllImport(GodotDllName)] internal static extern void godotsharp_internal_object_connect_event_signal(IntPtr obj, - godot_string_name* eventSignal); + in godot_string_name eventSignal); [DllImport(GodotDllName)] internal static extern Error godotsharp_internal_signal_awaiter_connect(IntPtr source, - ref godot_string_name signal, + in godot_string_name signal, IntPtr target, IntPtr awaiterHandlePtr); [DllImport(GodotDllName)] - public static extern void godotsharp_internal_tie_native_managed_to_unmanaged(IntPtr gcHandleIntPtr, - IntPtr unmanaged, godot_string_name* nativeName, godot_bool refCounted); + internal static extern void godotsharp_internal_tie_native_managed_to_unmanaged(IntPtr gcHandleIntPtr, + IntPtr unmanaged, in godot_string_name nativeName, godot_bool refCounted); [DllImport(GodotDllName)] - public static extern void godotsharp_internal_tie_user_managed_to_unmanaged(IntPtr gcHandleIntPtr, + internal static extern void godotsharp_internal_tie_user_managed_to_unmanaged(IntPtr gcHandleIntPtr, IntPtr unmanaged, IntPtr scriptPtr, godot_bool refCounted); [DllImport(GodotDllName)] - public static extern void godotsharp_internal_tie_managed_to_unmanaged_with_pre_setup( + internal static extern void godotsharp_internal_tie_managed_to_unmanaged_with_pre_setup( IntPtr gcHandleIntPtr, IntPtr unmanaged); [DllImport(GodotDllName)] - public static extern IntPtr godotsharp_internal_unmanaged_get_script_instance_managed(IntPtr p_unmanaged, - godot_bool* r_has_cs_script_instance); + internal static extern IntPtr godotsharp_internal_unmanaged_get_script_instance_managed(IntPtr p_unmanaged, + out godot_bool r_has_cs_script_instance); [DllImport(GodotDllName)] - public static extern IntPtr godotsharp_internal_unmanaged_get_instance_binding_managed(IntPtr p_unmanaged); + internal static extern IntPtr godotsharp_internal_unmanaged_get_instance_binding_managed(IntPtr p_unmanaged); [DllImport(GodotDllName)] - public static extern IntPtr godotsharp_internal_unmanaged_instance_binding_create_managed(IntPtr p_unmanaged, + internal static extern IntPtr godotsharp_internal_unmanaged_instance_binding_create_managed(IntPtr p_unmanaged, IntPtr oldGCHandlePtr); [DllImport(GodotDllName)] - public static extern IntPtr godotsharp_internal_new_csharp_script(); + internal static extern IntPtr godotsharp_internal_new_csharp_script(); [DllImport(GodotDllName)] - public static extern void godotsharp_array_filter_godot_objects_by_native(godot_string_name* p_native_name, - godot_array* p_input, godot_array* r_output); + internal static extern void godotsharp_array_filter_godot_objects_by_native(in godot_string_name p_native_name, + in godot_array p_input, out godot_array r_output); [DllImport(GodotDllName)] - public static extern void godotsharp_array_filter_godot_objects_by_non_native(godot_array* p_input, - godot_array* r_output); + internal static extern void godotsharp_array_filter_godot_objects_by_non_native(in godot_array p_input, + out godot_array r_output); [DllImport(GodotDllName)] public static extern void godotsharp_ref_destroy(ref godot_ref p_instance); [DllImport(GodotDllName)] - public static extern void godotsharp_string_name_new_from_string(godot_string_name* dest, godot_string* name); + public static extern void godotsharp_string_name_new_from_string(out godot_string_name r_dest, + in godot_string p_name); [DllImport(GodotDllName)] - public static extern void godotsharp_node_path_new_from_string(godot_node_path* dest, godot_string* name); + public static extern void godotsharp_node_path_new_from_string(out godot_node_path r_dest, + in godot_string p_name); [DllImport(GodotDllName)] - public static extern void godotsharp_string_name_as_string(godot_string* r_dest, godot_string_name* p_name); + public static extern void + godotsharp_string_name_as_string(out godot_string r_dest, in godot_string_name p_name); [DllImport(GodotDllName)] - public static extern void godotsharp_node_path_as_string(godot_string* r_dest, godot_node_path* p_np); + public static extern void godotsharp_node_path_as_string(out godot_string r_dest, in godot_node_path p_np); [DllImport(GodotDllName)] public static extern godot_packed_byte_array godotsharp_packed_byte_array_new_mem_copy(byte* p_src, @@ -124,16 +135,24 @@ namespace Godot.NativeInterop int p_length); [DllImport(GodotDllName)] - public static extern void godotsharp_packed_string_array_add(godot_packed_string_array* r_dest, - godot_string* p_element); + public static extern void godotsharp_packed_string_array_add(ref godot_packed_string_array r_dest, + in godot_string p_element); [DllImport(GodotDllName)] public static extern void godotsharp_callable_new_with_delegate(IntPtr p_delegate_handle, - godot_callable* r_callable); + out godot_callable r_callable); + + [DllImport(GodotDllName)] + internal static extern 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); [DllImport(GodotDllName)] - public static extern godot_bool godotsharp_callable_get_data_for_marshalling(godot_callable* p_callable, - IntPtr* r_delegate_handle, IntPtr* r_object, godot_string_name* r_name); + internal static extern 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); + + [DllImport(GodotDllName)] + internal static extern void godotsharp_callable_call_deferred(in godot_callable p_callable, + godot_variant** p_args, int p_arg_count); // GDNative functions @@ -145,219 +164,223 @@ namespace Godot.NativeInterop [DllImport(GodotDllName)] public static extern godot_variant godotsharp_method_bind_call(IntPtr p_method_bind, IntPtr p_instance, - godot_variant** p_args, int p_arg_count, godot_variant_call_error* p_call_error); + godot_variant** p_args, int p_arg_count, out godot_variant_call_error p_call_error); // variant.h [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_string_name(godot_variant* r_dest, godot_string_name* p_s); + public static extern void + godotsharp_variant_new_string_name(out godot_variant r_dest, in godot_string_name p_s); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_node_path(godot_variant* r_dest, godot_node_path* p_np); + public static extern void godotsharp_variant_new_node_path(out godot_variant r_dest, in godot_node_path p_np); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_object(godot_variant* r_dest, IntPtr p_obj); + public static extern void godotsharp_variant_new_object(out godot_variant r_dest, IntPtr p_obj); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_transform2d(godot_variant* r_dest, Transform2D* p_t2d); + public static extern void godotsharp_variant_new_transform2d(out godot_variant r_dest, in Transform2D p_t2d); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_vector4(godot_variant* r_dest, Vector4* p_vec4); + public static extern void godotsharp_variant_new_vector4(out godot_variant r_dest, in Vector4 p_vec4); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_vector4i(godot_variant* r_dest, Vector4i* p_vec4i); + public static extern void godotsharp_variant_new_vector4i(out godot_variant r_dest, in Vector4i p_vec4i); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_basis(godot_variant* r_dest, Basis* p_basis); + public static extern void godotsharp_variant_new_basis(out godot_variant r_dest, in Basis p_basis); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_transform3d(godot_variant* r_dest, Transform3D* p_trans); + public static extern void godotsharp_variant_new_transform3d(out godot_variant r_dest, in Transform3D p_trans); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_projection(godot_variant* r_dest, Projection* p_proj); + public static extern void godotsharp_variant_new_projection(out godot_variant r_dest, in Projection p_proj); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_aabb(godot_variant* r_dest, AABB* p_aabb); + public static extern void godotsharp_variant_new_aabb(out godot_variant r_dest, in AABB p_aabb); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_dictionary(godot_variant* r_dest, godot_dictionary* p_dict); + public static extern void godotsharp_variant_new_dictionary(out godot_variant r_dest, + in godot_dictionary p_dict); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_array(godot_variant* r_dest, godot_array* p_arr); + public static extern void godotsharp_variant_new_array(out godot_variant r_dest, in godot_array p_arr); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_packed_byte_array(godot_variant* r_dest, - godot_packed_byte_array* p_pba); + public static extern void godotsharp_variant_new_packed_byte_array(out godot_variant r_dest, + in godot_packed_byte_array p_pba); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_packed_int32_array(godot_variant* r_dest, - godot_packed_int32_array* p_pia); + public static extern void godotsharp_variant_new_packed_int32_array(out godot_variant r_dest, + in godot_packed_int32_array p_pia); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_packed_int64_array(godot_variant* r_dest, - godot_packed_int64_array* p_pia); + public static extern void godotsharp_variant_new_packed_int64_array(out godot_variant r_dest, + in godot_packed_int64_array p_pia); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_packed_float32_array(godot_variant* r_dest, - godot_packed_float32_array* p_pra); + public static extern void godotsharp_variant_new_packed_float32_array(out godot_variant r_dest, + in godot_packed_float32_array p_pra); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_packed_float64_array(godot_variant* r_dest, - godot_packed_float64_array* p_pra); + public static extern void godotsharp_variant_new_packed_float64_array(out godot_variant r_dest, + in godot_packed_float64_array p_pra); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_packed_string_array(godot_variant* r_dest, - godot_packed_string_array* p_psa); + public static extern void godotsharp_variant_new_packed_string_array(out godot_variant r_dest, + in godot_packed_string_array p_psa); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_packed_vector2_array(godot_variant* r_dest, - godot_packed_vector2_array* p_pv2a); + public static extern void godotsharp_variant_new_packed_vector2_array(out godot_variant r_dest, + in godot_packed_vector2_array p_pv2a); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_packed_vector3_array(godot_variant* r_dest, - godot_packed_vector3_array* p_pv3a); + public static extern void godotsharp_variant_new_packed_vector3_array(out godot_variant r_dest, + in godot_packed_vector3_array p_pv3a); [DllImport(GodotDllName)] - public static extern void godotsharp_variant_new_packed_color_array(godot_variant* r_dest, - godot_packed_color_array* p_pca); + public static extern void godotsharp_variant_new_packed_color_array(out godot_variant r_dest, + in godot_packed_color_array p_pca); [DllImport(GodotDllName)] - public static extern godot_bool godotsharp_variant_as_bool(godot_variant* p_self); + public static extern godot_bool godotsharp_variant_as_bool(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Int64 godotsharp_variant_as_int(godot_variant* p_self); + public static extern Int64 godotsharp_variant_as_int(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern double godotsharp_variant_as_float(godot_variant* p_self); + public static extern double godotsharp_variant_as_float(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_string godotsharp_variant_as_string(godot_variant* p_self); + public static extern godot_string godotsharp_variant_as_string(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Vector2 godotsharp_variant_as_vector2(godot_variant* p_self); + public static extern Vector2 godotsharp_variant_as_vector2(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Vector2i godotsharp_variant_as_vector2i(godot_variant* p_self); + public static extern Vector2i godotsharp_variant_as_vector2i(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Rect2 godotsharp_variant_as_rect2(godot_variant* p_self); + public static extern Rect2 godotsharp_variant_as_rect2(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Rect2i godotsharp_variant_as_rect2i(godot_variant* p_self); + public static extern Rect2i godotsharp_variant_as_rect2i(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Vector3 godotsharp_variant_as_vector3(godot_variant* p_self); + public static extern Vector3 godotsharp_variant_as_vector3(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Vector3i godotsharp_variant_as_vector3i(godot_variant* p_self); + public static extern Vector3i godotsharp_variant_as_vector3i(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Transform2D godotsharp_variant_as_transform2d(godot_variant* p_self); + public static extern Transform2D godotsharp_variant_as_transform2d(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Vector4 godotsharp_variant_as_vector4(godot_variant* p_self); + public static extern Vector4 godotsharp_variant_as_vector4(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Vector4i godotsharp_variant_as_vector4i(godot_variant* p_self); + public static extern Vector4i godotsharp_variant_as_vector4i(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Plane godotsharp_variant_as_plane(godot_variant* p_self); + public static extern Plane godotsharp_variant_as_plane(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Quaternion godotsharp_variant_as_quaternion(godot_variant* p_self); + public static extern Quaternion godotsharp_variant_as_quaternion(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern AABB godotsharp_variant_as_aabb(godot_variant* p_self); + public static extern AABB godotsharp_variant_as_aabb(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Basis godotsharp_variant_as_basis(godot_variant* p_self); + public static extern Basis godotsharp_variant_as_basis(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Transform3D godotsharp_variant_as_transform3d(godot_variant* p_self); + public static extern Transform3D godotsharp_variant_as_transform3d(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Projection godotsharp_variant_as_projection(godot_variant* p_self); + public static extern Projection godotsharp_variant_as_projection(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern Color godotsharp_variant_as_color(godot_variant* p_self); + public static extern Color godotsharp_variant_as_color(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_string_name godotsharp_variant_as_string_name(godot_variant* p_self); + public static extern godot_string_name godotsharp_variant_as_string_name(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_node_path godotsharp_variant_as_node_path(godot_variant* p_self); + public static extern godot_node_path godotsharp_variant_as_node_path(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern RID godotsharp_variant_as_rid(godot_variant* p_self); + public static extern RID godotsharp_variant_as_rid(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_callable godotsharp_variant_as_callable(godot_variant* p_self); + public static extern godot_callable godotsharp_variant_as_callable(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_signal godotsharp_variant_as_signal(godot_variant* p_self); + public static extern godot_signal godotsharp_variant_as_signal(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_dictionary godotsharp_variant_as_dictionary(godot_variant* p_self); + public static extern godot_dictionary godotsharp_variant_as_dictionary(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_array godotsharp_variant_as_array(godot_variant* p_self); + public static extern godot_array godotsharp_variant_as_array(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_packed_byte_array godotsharp_variant_as_packed_byte_array(godot_variant* p_self); + public static extern godot_packed_byte_array godotsharp_variant_as_packed_byte_array(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_packed_int32_array godotsharp_variant_as_packed_int32_array(godot_variant* p_self); + public static extern godot_packed_int32_array godotsharp_variant_as_packed_int32_array(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_packed_int64_array godotsharp_variant_as_packed_int64_array(godot_variant* p_self); + public static extern godot_packed_int64_array godotsharp_variant_as_packed_int64_array(in godot_variant p_self); [DllImport(GodotDllName)] public static extern godot_packed_float32_array godotsharp_variant_as_packed_float32_array( - godot_variant* p_self); + in godot_variant p_self); [DllImport(GodotDllName)] public static extern godot_packed_float64_array godotsharp_variant_as_packed_float64_array( - godot_variant* p_self); + in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_packed_string_array godotsharp_variant_as_packed_string_array(godot_variant* p_self); + public static extern godot_packed_string_array godotsharp_variant_as_packed_string_array( + in godot_variant p_self); [DllImport(GodotDllName)] public static extern godot_packed_vector2_array godotsharp_variant_as_packed_vector2_array( - godot_variant* p_self); + in godot_variant p_self); [DllImport(GodotDllName)] public static extern godot_packed_vector3_array godotsharp_variant_as_packed_vector3_array( - godot_variant* p_self); + in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_packed_color_array godotsharp_variant_as_packed_color_array(godot_variant* p_self); + public static extern godot_packed_color_array godotsharp_variant_as_packed_color_array(in godot_variant p_self); [DllImport(GodotDllName)] - public static extern godot_bool godotsharp_variant_equals(godot_variant* p_a, godot_variant* p_b); + public static extern godot_bool godotsharp_variant_equals(in godot_variant p_a, in godot_variant p_b); // string.h [DllImport(GodotDllName)] - public static extern void godotsharp_string_new_with_utf16_chars(godot_string* r_dest, char* p_contents); + public static extern void godotsharp_string_new_with_utf16_chars(out godot_string r_dest, char* p_contents); // string_name.h [DllImport(GodotDllName)] - public static extern void godotsharp_string_name_new_copy(godot_string_name* r_dest, godot_string_name* p_src); + public static extern void godotsharp_string_name_new_copy(out godot_string_name r_dest, + in godot_string_name p_src); // node_path.h [DllImport(GodotDllName)] - public static extern void godotsharp_node_path_new_copy(godot_node_path* r_dest, godot_node_path* p_src); + public static extern void godotsharp_node_path_new_copy(out godot_node_path r_dest, in godot_node_path p_src); // array.h [DllImport(GodotDllName)] - public static extern void godotsharp_array_new(godot_array* p_self); + public static extern void godotsharp_array_new(out godot_array r_dest); [DllImport(GodotDllName)] - public static extern void godotsharp_array_new_copy(godot_array* r_dest, godot_array* p_src); + public static extern void godotsharp_array_new_copy(out godot_array r_dest, in godot_array p_src); [DllImport(GodotDllName)] public static extern godot_variant* godotsharp_array_ptrw(ref godot_array p_self); @@ -365,10 +388,11 @@ namespace Godot.NativeInterop // dictionary.h [DllImport(GodotDllName)] - public static extern void godotsharp_dictionary_new(godot_dictionary* p_self); + public static extern void godotsharp_dictionary_new(out godot_dictionary r_dest); [DllImport(GodotDllName)] - public static extern void godotsharp_dictionary_new_copy(godot_dictionary* r_dest, godot_dictionary* p_src); + public static extern void godotsharp_dictionary_new_copy(out godot_dictionary r_dest, + in godot_dictionary p_src); // destroy functions @@ -426,17 +450,17 @@ namespace Godot.NativeInterop // Array [DllImport(GodotDllName)] - public static extern int godotsharp_array_add(ref godot_array p_self, godot_variant* p_item); + public static extern int godotsharp_array_add(ref godot_array p_self, in godot_variant p_item); [DllImport(GodotDllName)] public static extern void godotsharp_array_duplicate(ref godot_array p_self, godot_bool p_deep, out godot_array r_dest); [DllImport(GodotDllName)] - public static extern int godotsharp_array_index_of(ref godot_array p_self, godot_variant* p_item); + public static extern int godotsharp_array_index_of(ref godot_array p_self, in godot_variant p_item); [DllImport(GodotDllName)] - public static extern void godotsharp_array_insert(ref godot_array p_self, int p_index, godot_variant* p_item); + public static extern void godotsharp_array_insert(ref godot_array p_self, int p_index, in godot_variant p_item); [DllImport(GodotDllName)] public static extern void godotsharp_array_remove_at(ref godot_array p_self, int p_index); @@ -448,18 +472,18 @@ namespace Godot.NativeInterop public static extern Error godotsharp_array_shuffle(ref godot_array p_self); [DllImport(GodotDllName)] - public static extern void godotsharp_array_to_string(ref godot_array p_self, godot_string* r_str); + public static extern void godotsharp_array_to_string(ref godot_array p_self, out godot_string r_str); // Dictionary [DllImport(GodotDllName)] public static extern godot_bool godotsharp_dictionary_try_get_value(ref godot_dictionary p_self, - godot_variant* p_key, + in godot_variant p_key, out godot_variant r_value); [DllImport(GodotDllName)] - public static extern void godotsharp_dictionary_set_value(ref godot_dictionary p_self, godot_variant* p_key, - godot_variant* p_value); + public static extern void godotsharp_dictionary_set_value(ref godot_dictionary p_self, in godot_variant p_key, + in godot_variant p_value); [DllImport(GodotDllName)] public static extern void godotsharp_dictionary_keys(ref godot_dictionary p_self, out godot_array r_dest); @@ -475,15 +499,15 @@ namespace Godot.NativeInterop out godot_variant r_key, out godot_variant r_value); [DllImport(GodotDllName)] - public static extern void godotsharp_dictionary_add(ref godot_dictionary p_self, godot_variant* p_key, - godot_variant* p_value); + public static extern void godotsharp_dictionary_add(ref godot_dictionary p_self, in godot_variant p_key, + in godot_variant p_value); [DllImport(GodotDllName)] public static extern void godotsharp_dictionary_clear(ref godot_dictionary p_self); [DllImport(GodotDllName)] public static extern godot_bool godotsharp_dictionary_contains_key(ref godot_dictionary p_self, - godot_variant* p_key); + in godot_variant p_key); [DllImport(GodotDllName)] public static extern void godotsharp_dictionary_duplicate(ref godot_dictionary p_self, godot_bool p_deep, @@ -491,149 +515,153 @@ namespace Godot.NativeInterop [DllImport(GodotDllName)] public static extern godot_bool godotsharp_dictionary_remove_key(ref godot_dictionary p_self, - godot_variant* p_key); + in godot_variant p_key); [DllImport(GodotDllName)] - public static extern void godotsharp_dictionary_to_string(ref godot_dictionary p_self, godot_string* r_str); + public static extern void godotsharp_dictionary_to_string(ref godot_dictionary p_self, out godot_string r_str); // StringExtensions [DllImport(GodotDllName)] - public static extern void godotsharp_string_md5_buffer(godot_string* p_self, - godot_packed_byte_array* r_md5_buffer); + public static extern void godotsharp_string_md5_buffer(in godot_string p_self, + out godot_packed_byte_array r_md5_buffer); [DllImport(GodotDllName)] - public static extern void godotsharp_string_md5_text(godot_string* p_self, godot_string* r_md5_text); + public static extern void godotsharp_string_md5_text(in godot_string p_self, out godot_string r_md5_text); [DllImport(GodotDllName)] - public static extern int godotsharp_string_rfind(godot_string* p_self, godot_string* p_what, int p_from); + public static extern int godotsharp_string_rfind(in godot_string p_self, in godot_string p_what, int p_from); [DllImport(GodotDllName)] - public static extern int godotsharp_string_rfindn(godot_string* p_self, godot_string* p_what, int p_from); + public static extern int godotsharp_string_rfindn(in godot_string p_self, in godot_string p_what, int p_from); [DllImport(GodotDllName)] - public static extern void godotsharp_string_sha256_buffer(godot_string* p_self, - godot_packed_byte_array* r_sha256_buffer); + public static extern void godotsharp_string_sha256_buffer(in godot_string p_self, + out godot_packed_byte_array r_sha256_buffer); [DllImport(GodotDllName)] - public static extern void godotsharp_string_sha256_text(godot_string* p_self, godot_string* r_sha256_text); + public static extern void godotsharp_string_sha256_text(in godot_string p_self, + out godot_string r_sha256_text); [DllImport(GodotDllName)] - public static extern void godotsharp_string_simplify_path(godot_string* p_self, godot_string* r_simplified_path); + public static extern void godotsharp_string_simplify_path(in godot_string p_self, + out godot_string r_simplified_path); // NodePath [DllImport(GodotDllName)] - public static extern void godotsharp_node_path_get_as_property_path(ref godot_node_path p_self, + public static extern void godotsharp_node_path_get_as_property_path(in godot_node_path p_self, ref godot_node_path r_dest); [DllImport(GodotDllName)] - public static extern void godotsharp_node_path_get_concatenated_names(ref godot_node_path p_self, - godot_string* r_names); + public static extern void godotsharp_node_path_get_concatenated_names(in godot_node_path p_self, + out godot_string r_names); [DllImport(GodotDllName)] - public static extern void godotsharp_node_path_get_concatenated_subnames(ref godot_node_path p_self, - godot_string* r_subnames); + public static extern void godotsharp_node_path_get_concatenated_subnames(in godot_node_path p_self, + out godot_string r_subnames); [DllImport(GodotDllName)] - public static extern void godotsharp_node_path_get_name(ref godot_node_path p_self, int p_idx, - godot_string* r_name); + public static extern void godotsharp_node_path_get_name(in godot_node_path p_self, int p_idx, + out godot_string r_name); [DllImport(GodotDllName)] - public static extern int godotsharp_node_path_get_name_count(ref godot_node_path p_self); + public static extern int godotsharp_node_path_get_name_count(in godot_node_path p_self); [DllImport(GodotDllName)] - public static extern void godotsharp_node_path_get_subname(ref godot_node_path p_self, int p_idx, - godot_string* r_subname); + public static extern void godotsharp_node_path_get_subname(in godot_node_path p_self, int p_idx, + out godot_string r_subname); [DllImport(GodotDllName)] - public static extern int godotsharp_node_path_get_subname_count(ref godot_node_path p_self); + public static extern int godotsharp_node_path_get_subname_count(in godot_node_path p_self); [DllImport(GodotDllName)] - public static extern godot_bool godotsharp_node_path_is_absolute(ref godot_node_path p_self); + public static extern godot_bool godotsharp_node_path_is_absolute(in godot_node_path p_self); // GD, etc [DllImport(GodotDllName)] - public static extern void godotsharp_bytes2var(godot_packed_byte_array* p_bytes, godot_bool p_allow_objects, - godot_variant* r_ret); + internal static extern void godotsharp_bytes2var(in godot_packed_byte_array p_bytes, + godot_bool p_allow_objects, + out godot_variant r_ret); [DllImport(GodotDllName)] - public static extern void godotsharp_convert(godot_variant* p_what, int p_type, godot_variant* r_ret); + internal static extern void godotsharp_convert(in godot_variant p_what, int p_type, + out godot_variant r_ret); [DllImport(GodotDllName)] - public static extern int godotsharp_hash(godot_variant* var); + internal static extern int godotsharp_hash(in godot_variant p_var); [DllImport(GodotDllName)] - public static extern IntPtr godotsharp_instance_from_id(ulong instanceId); + internal static extern IntPtr godotsharp_instance_from_id(ulong p_instance_id); [DllImport(GodotDllName)] - public static extern void godotsharp_print(godot_string* p_what); + internal static extern void godotsharp_print(in godot_string p_what); [DllImport(GodotDllName)] - public static extern void godotsharp_print_rich(godot_string* p_what); + public static extern void godotsharp_print_rich(in godot_string p_what); [DllImport(GodotDllName)] - public static extern void godotsharp_printerr(godot_string* p_what); + internal static extern void godotsharp_printerr(in godot_string p_what); [DllImport(GodotDllName)] - public static extern void godotsharp_printraw(godot_string* p_what); + internal static extern void godotsharp_printraw(in godot_string p_what); [DllImport(GodotDllName)] - public static extern void godotsharp_prints(godot_string* p_what); + internal static extern void godotsharp_prints(in godot_string p_what); [DllImport(GodotDllName)] - public static extern void godotsharp_printt(godot_string* p_what); + internal static extern void godotsharp_printt(in godot_string p_what); [DllImport(GodotDllName)] - public static extern float godotsharp_randf(); + internal static extern float godotsharp_randf(); [DllImport(GodotDllName)] - public static extern uint godotsharp_randi(); + internal static extern uint godotsharp_randi(); [DllImport(GodotDllName)] - public static extern void godotsharp_randomize(); + internal static extern void godotsharp_randomize(); [DllImport(GodotDllName)] - public static extern double godotsharp_randf_range(double from, double to); + internal static extern double godotsharp_randf_range(double from, double to); [DllImport(GodotDllName)] - public static extern double godotsharp_randfn(double mean, double deviation); + internal static extern double godotsharp_randfn(double mean, double deviation); [DllImport(GodotDllName)] - public static extern int godotsharp_randi_range(int from, int to); + internal static extern int godotsharp_randi_range(int from, int to); [DllImport(GodotDllName)] - public static extern uint godotsharp_rand_from_seed(ulong seed, out ulong newSeed); + internal static extern uint godotsharp_rand_from_seed(ulong seed, out ulong newSeed); [DllImport(GodotDllName)] - public static extern void godotsharp_seed(ulong seed); + internal static extern void godotsharp_seed(ulong seed); [DllImport(GodotDllName)] - public static extern void godotsharp_weakref(IntPtr obj, godot_ref* r_weak_ref); + internal static extern void godotsharp_weakref(IntPtr p_obj, out godot_ref r_weak_ref); [DllImport(GodotDllName)] - public static extern string godotsharp_str(godot_array* p_what, godot_string* r_ret); + internal static extern void godotsharp_str(in godot_array p_what, out godot_string r_ret); [DllImport(GodotDllName)] - public static extern void godotsharp_str2var(godot_string* p_str, godot_variant* r_ret); + internal static extern void godotsharp_str2var(in godot_string p_str, out godot_variant r_ret); [DllImport(GodotDllName)] - public static extern void godotsharp_var2bytes(godot_variant* what, godot_bool fullObjects, - godot_packed_byte_array* bytes); + internal static extern void godotsharp_var2bytes(in godot_variant p_what, godot_bool p_full_objects, + out godot_packed_byte_array r_bytes); [DllImport(GodotDllName)] - public static extern void godotsharp_var2str(godot_variant* var, godot_string* r_ret); + internal static extern void godotsharp_var2str(in godot_variant p_var, out godot_string r_ret); [DllImport(GodotDllName)] - public static extern void godotsharp_pusherror(godot_string* type); + internal static extern void godotsharp_pusherror(in godot_string p_str); [DllImport(GodotDllName)] - public static extern void godotsharp_pushwarning(godot_string* type); + internal static extern void godotsharp_pushwarning(in godot_string p_str); // Object [DllImport(GodotDllName)] - public static extern string godotsharp_object_to_string(IntPtr ptr, godot_string* r_str); + public static extern void godotsharp_object_to_string(IntPtr ptr, out godot_string r_str); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs index 089883c7e8..0c49660cf0 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs @@ -1,83 +1,60 @@ -using System; -using System.Runtime.CompilerServices; - // ReSharper disable InconsistentNaming namespace Godot.NativeInterop { - public static unsafe partial class NativeFuncs + public static partial class NativeFuncs { - public static godot_string_name godotsharp_string_name_new_copy(godot_string_name* src) + public static godot_string_name godotsharp_string_name_new_copy(in godot_string_name src) { - godot_string_name ret; - godotsharp_string_name_new_copy(&ret, src); + if (src.IsEmpty) + return default; + godotsharp_string_name_new_copy(out godot_string_name ret, src); return ret; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static godot_string_name godotsharp_string_name_new_copy(godot_string_name src) - => godotsharp_string_name_new_copy(&src); - - public static godot_node_path godotsharp_node_path_new_copy(godot_node_path* src) + public static godot_node_path godotsharp_node_path_new_copy(in godot_node_path src) { - godot_node_path ret; - godotsharp_node_path_new_copy(&ret, src); + if (src.IsEmpty) + return default; + godotsharp_node_path_new_copy(out godot_node_path ret, src); return ret; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static godot_node_path godotsharp_node_path_new_copy(godot_node_path src) - => godotsharp_node_path_new_copy(&src); - public static godot_array godotsharp_array_new() { - godot_array ret; - godotsharp_array_new(&ret); + godotsharp_array_new(out godot_array ret); return ret; } - public static godot_array godotsharp_array_new_copy(godot_array* src) + public static godot_array godotsharp_array_new_copy(in godot_array src) { - godot_array ret; - godotsharp_array_new_copy(&ret, src); + godotsharp_array_new_copy(out godot_array ret, src); return ret; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static godot_array godotsharp_array_new_copy(godot_array src) - => godotsharp_array_new_copy(&src); - public static godot_dictionary godotsharp_dictionary_new() { - godot_dictionary ret; - godotsharp_dictionary_new(&ret); + godotsharp_dictionary_new(out godot_dictionary ret); return ret; } - public static godot_dictionary godotsharp_dictionary_new_copy(godot_dictionary* src) + public static godot_dictionary godotsharp_dictionary_new_copy(in godot_dictionary src) { - godot_dictionary ret; - godotsharp_dictionary_new_copy(&ret, src); + godotsharp_dictionary_new_copy(out godot_dictionary ret, src); return ret; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static godot_dictionary godotsharp_dictionary_new_copy(godot_dictionary src) - => godotsharp_dictionary_new_copy(&src); - public static godot_string_name godotsharp_string_name_new_from_string(string name) { - godot_string_name ret; - using godot_string src = Marshaling.mono_string_to_godot(name); - godotsharp_string_name_new_from_string(&ret, &src); + using godot_string src = Marshaling.ConvertStringToNative(name); + godotsharp_string_name_new_from_string(out godot_string_name ret, src); return ret; } public static godot_node_path godotsharp_node_path_new_from_string(string name) { - godot_node_path ret; - using godot_string src = Marshaling.mono_string_to_godot(name); - godotsharp_node_path_new_from_string(&ret, &src); + using godot_string src = Marshaling.ConvertStringToNative(name); + godotsharp_node_path_new_from_string(out godot_node_path ret, src); return ret; } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeVariantPtrArgs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeVariantPtrArgs.cs new file mode 100644 index 0000000000..422df74c23 --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeVariantPtrArgs.cs @@ -0,0 +1,20 @@ +using System.Runtime.CompilerServices; + +namespace Godot.NativeInterop +{ + // Our source generators will add trampolines methods that access variant arguments. + // This struct makes that possible without having to enable `AllowUnsafeBlocks` in game projects. + + public unsafe ref struct NativeVariantPtrArgs + { + private godot_variant** _args; + + internal NativeVariantPtrArgs(godot_variant** args) => _args = args; + + public ref godot_variant this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref *_args[index]; + } + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantSpanHelpers.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantSpanHelpers.cs index 2814f9d506..46f31bbf4e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantSpanHelpers.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantSpanHelpers.cs @@ -2,13 +2,13 @@ using System; namespace Godot.NativeInterop { - internal ref struct VariantSpanDisposer + internal readonly ref struct VariantSpanDisposer { - private readonly Span<godot_variant> _variantSpan; + private readonly Span<godot_variant.movable> _variantSpan; // IMPORTANT: The span element must be default initialized. // Make sure call Clear() on the span if it was created with stackalloc. - public VariantSpanDisposer(Span<godot_variant> variantSpan) + public VariantSpanDisposer(Span<godot_variant.movable> variantSpan) { _variantSpan = variantSpan; } @@ -16,7 +16,7 @@ namespace Godot.NativeInterop public void Dispose() { for (int i = 0; i < _variantSpan.Length; i++) - _variantSpan[i].Dispose(); + _variantSpan[i].DangerousSelfRef.Dispose(); } } @@ -24,7 +24,7 @@ namespace Godot.NativeInterop { // Used to make sure we always initialize the span values to the default, // as we need that in order to safely dispose all elements after. - public static Span<godot_variant> Cleared(this Span<godot_variant> span) + public static Span<godot_variant.movable> Cleared(this Span<godot_variant.movable> span) { span.Clear(); return span; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs index e52454a2e3..f69cc40314 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.CompilerServices; // ReSharper disable InconsistentNaming @@ -8,378 +7,353 @@ namespace Godot.NativeInterop public static class VariantUtils { public static godot_variant CreateFromRID(RID from) - => new() { _type = Variant.Type.Rid, _data = { _m_rid = from } }; + => new() { Type = Variant.Type.Rid, RID = from }; public static godot_variant CreateFromBool(bool from) - => new() { _type = Variant.Type.Bool, _data = { _bool = from.ToGodotBool() } }; + => new() { Type = Variant.Type.Bool, Bool = from.ToGodotBool() }; public static godot_variant CreateFromInt(long from) - => new() { _type = Variant.Type.Int, _data = { _int = from } }; + => new() { Type = Variant.Type.Int, Int = from }; public static godot_variant CreateFromInt(ulong from) - => new() { _type = Variant.Type.Int, _data = { _int = (long)from } }; + => new() { Type = Variant.Type.Int, Int = (long)from }; public static godot_variant CreateFromFloat(double from) - => new() { _type = Variant.Type.Float, _data = { _float = from } }; + => new() { Type = Variant.Type.Float, Float = from }; public static godot_variant CreateFromVector2(Vector2 from) - => new() { _type = Variant.Type.Vector2, _data = { _m_vector2 = from } }; + => new() { Type = Variant.Type.Vector2, Vector2 = from }; public static godot_variant CreateFromVector2i(Vector2i from) - => new() { _type = Variant.Type.Vector2i, _data = { _m_vector2i = from } }; + => new() { Type = Variant.Type.Vector2i, Vector2i = from }; public static godot_variant CreateFromVector3(Vector3 from) - => new() { _type = Variant.Type.Vector3, _data = { _m_vector3 = from } }; + => new() { Type = Variant.Type.Vector3, Vector3 = from }; public static godot_variant CreateFromVector3i(Vector3i from) - => new() { _type = Variant.Type.Vector3i, _data = { _m_vector3i = from } }; + => new() { Type = Variant.Type.Vector3i, Vector3i = from }; public static godot_variant CreateFromRect2(Rect2 from) - => new() { _type = Variant.Type.Rect2, _data = { _m_rect2 = from } }; + => new() { Type = Variant.Type.Rect2, Rect2 = from }; public static godot_variant CreateFromRect2i(Rect2i from) - => new() { _type = Variant.Type.Rect2i, _data = { _m_rect2i = from } }; + => new() { Type = Variant.Type.Rect2i, Rect2i = from }; public static godot_variant CreateFromQuaternion(Quaternion from) - => new() { _type = Variant.Type.Quaternion, _data = { _m_quaternion = from } }; + => new() { Type = Variant.Type.Quaternion, Quaternion = from }; public static godot_variant CreateFromColor(Color from) - => new() { _type = Variant.Type.Color, _data = { _m_color = from } }; + => new() { Type = Variant.Type.Color, Color = from }; public static godot_variant CreateFromPlane(Plane from) - => new() { _type = Variant.Type.Plane, _data = { _m_plane = from } }; + => new() { Type = Variant.Type.Plane, Plane = from }; - public static unsafe godot_variant CreateFromTransform2D(Transform2D from) + public static godot_variant CreateFromTransform2D(Transform2D from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_transform2d(&ret, &from); + NativeFuncs.godotsharp_variant_new_transform2d(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromVector4(Vector4 from) + public static godot_variant CreateFromVector4(Vector4 from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_vector4(&ret, &from); + NativeFuncs.godotsharp_variant_new_vector4(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromVector4i(Vector4i from) + public static godot_variant CreateFromVector4i(Vector4i from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_vector4i(&ret, &from); + NativeFuncs.godotsharp_variant_new_vector4i(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromBasis(Basis from) + public static godot_variant CreateFromBasis(Basis from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_basis(&ret, &from); + NativeFuncs.godotsharp_variant_new_basis(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromTransform3D(Transform3D from) + public static godot_variant CreateFromTransform3D(Transform3D from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_transform3d(&ret, &from); + NativeFuncs.godotsharp_variant_new_transform3d(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromProjection(Projection from) + public static godot_variant CreateFromProjection(Projection from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_projection(&ret, &from); + NativeFuncs.godotsharp_variant_new_projection(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromAABB(AABB from) + public static godot_variant CreateFromAABB(AABB from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_aabb(&ret, &from); + NativeFuncs.godotsharp_variant_new_aabb(out godot_variant ret, from); return ret; } // Explicit name to make it very clear public static godot_variant CreateFromCallableTakingOwnershipOfDisposableValue(godot_callable from) - => new() { _type = Variant.Type.Callable, _data = { _m_callable = from } }; + => new() { Type = Variant.Type.Callable, Callable = from }; // Explicit name to make it very clear public static godot_variant CreateFromSignalTakingOwnershipOfDisposableValue(godot_signal from) - => new() { _type = Variant.Type.Signal, _data = { _m_signal = from } }; + => new() { Type = Variant.Type.Signal, Signal = from }; // Explicit name to make it very clear public static godot_variant CreateFromStringTakingOwnershipOfDisposableValue(godot_string from) - => new() { _type = Variant.Type.String, _data = { _m_string = from } }; + => new() { Type = Variant.Type.String, String = from }; - public static unsafe godot_variant CreateFromPackedByteArray(godot_packed_byte_array* from) + public static godot_variant CreateFromPackedByteArray(in godot_packed_byte_array from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_packed_byte_array(&ret, from); + NativeFuncs.godotsharp_variant_new_packed_byte_array(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromPackedInt32Array(godot_packed_int32_array* from) + public static godot_variant CreateFromPackedInt32Array(in godot_packed_int32_array from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_packed_int32_array(&ret, from); + NativeFuncs.godotsharp_variant_new_packed_int32_array(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromPackedInt64Array(godot_packed_int64_array* from) + public static godot_variant CreateFromPackedInt64Array(in godot_packed_int64_array from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_packed_int64_array(&ret, from); + NativeFuncs.godotsharp_variant_new_packed_int64_array(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromPackedFloat32Array(godot_packed_float32_array* from) + public static godot_variant CreateFromPackedFloat32Array(in godot_packed_float32_array from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_packed_float32_array(&ret, from); + NativeFuncs.godotsharp_variant_new_packed_float32_array(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromPackedFloat64Array(godot_packed_float64_array* from) + public static godot_variant CreateFromPackedFloat64Array(in godot_packed_float64_array from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_packed_float64_array(&ret, from); + NativeFuncs.godotsharp_variant_new_packed_float64_array(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromPackedStringArray(godot_packed_string_array* from) + public static godot_variant CreateFromPackedStringArray(in godot_packed_string_array from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_packed_string_array(&ret, from); + NativeFuncs.godotsharp_variant_new_packed_string_array(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromPackedVector2Array(godot_packed_vector2_array* from) + public static godot_variant CreateFromPackedVector2Array(in godot_packed_vector2_array from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_packed_vector2_array(&ret, from); + NativeFuncs.godotsharp_variant_new_packed_vector2_array(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromPackedVector3Array(godot_packed_vector3_array* from) + public static godot_variant CreateFromPackedVector3Array(in godot_packed_vector3_array from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_packed_vector3_array(&ret, from); + NativeFuncs.godotsharp_variant_new_packed_vector3_array(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromPackedColorArray(godot_packed_color_array* from) + public static godot_variant CreateFromPackedColorArray(in godot_packed_color_array from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_packed_color_array(&ret, from); + NativeFuncs.godotsharp_variant_new_packed_color_array(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromArray(godot_array* from) + public static godot_variant CreateFromArray(godot_array from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_array(&ret, from); + NativeFuncs.godotsharp_variant_new_array(out godot_variant ret, from); return ret; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe godot_variant CreateFromArray(godot_array from) - => CreateFromArray(&from); - - public static unsafe godot_variant CreateFromDictionary(godot_dictionary* from) + public static godot_variant CreateFromDictionary(godot_dictionary from) { - godot_variant ret; - NativeFuncs.godotsharp_variant_new_dictionary(&ret, from); + NativeFuncs.godotsharp_variant_new_dictionary(out godot_variant ret, from); return ret; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe godot_variant CreateFromDictionary(godot_dictionary from) - => CreateFromDictionary(&from); - - public static unsafe godot_variant CreateFromStringName(ref godot_string_name arg1) + public static godot_variant CreateFromStringName(godot_string_name from) { - godot_variant ret; - godot_string_name src = arg1; - NativeFuncs.godotsharp_variant_new_string_name(&ret, &src); + NativeFuncs.godotsharp_variant_new_string_name(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromNodePath(ref godot_node_path arg1) + public static godot_variant CreateFromNodePath(godot_node_path from) { - godot_variant ret; - godot_node_path src = arg1; - NativeFuncs.godotsharp_variant_new_node_path(&ret, &src); + NativeFuncs.godotsharp_variant_new_node_path(out godot_variant ret, from); return ret; } - public static unsafe godot_variant CreateFromGodotObject(IntPtr from) + public static godot_variant CreateFromGodotObject(IntPtr from) { if (from == IntPtr.Zero) return new godot_variant(); - godot_variant ret; - NativeFuncs.godotsharp_variant_new_object(&ret, from); + NativeFuncs.godotsharp_variant_new_object(out godot_variant ret, from); return ret; } // We avoid the internal call if the stored type is the same we want. - public static unsafe bool ConvertToBool(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Bool ? - (*p_var)._data._bool.ToBool() : + public static bool ConvertToBool(in godot_variant p_var) + => p_var.Type == Variant.Type.Bool ? + p_var.Bool.ToBool() : NativeFuncs.godotsharp_variant_as_bool(p_var).ToBool(); - public static unsafe char ConvertToChar(godot_variant* p_var) - => (char)((*p_var)._type == Variant.Type.Int ? - (*p_var)._data._int : + public static char ConvertToChar(in godot_variant p_var) + => (char)(p_var.Type == Variant.Type.Int ? + p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var)); - public static unsafe sbyte ConvertToInt8(godot_variant* p_var) - => (sbyte)((*p_var)._type == Variant.Type.Int ? - (*p_var)._data._int : + public static sbyte ConvertToInt8(in godot_variant p_var) + => (sbyte)(p_var.Type == Variant.Type.Int ? + p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var)); - public static unsafe Int16 ConvertToInt16(godot_variant* p_var) - => (Int16)((*p_var)._type == Variant.Type.Int ? - (*p_var)._data._int : + public static Int16 ConvertToInt16(in godot_variant p_var) + => (Int16)(p_var.Type == Variant.Type.Int ? + p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var)); - public static unsafe Int32 ConvertToInt32(godot_variant* p_var) - => (Int32)((*p_var)._type == Variant.Type.Int ? - (*p_var)._data._int : + public static Int32 ConvertToInt32(in godot_variant p_var) + => (Int32)(p_var.Type == Variant.Type.Int ? + p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var)); - public static unsafe Int64 ConvertToInt64(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Int ? (*p_var)._data._int : NativeFuncs.godotsharp_variant_as_int(p_var); + public static Int64 ConvertToInt64(in godot_variant p_var) + => p_var.Type == Variant.Type.Int ? p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var); - public static unsafe byte ConvertToUInt8(godot_variant* p_var) - => (byte)((*p_var)._type == Variant.Type.Int ? - (*p_var)._data._int : + public static byte ConvertToUInt8(in godot_variant p_var) + => (byte)(p_var.Type == Variant.Type.Int ? + p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var)); - public static unsafe UInt16 ConvertToUInt16(godot_variant* p_var) - => (UInt16)((*p_var)._type == Variant.Type.Int ? - (*p_var)._data._int : + public static UInt16 ConvertToUInt16(in godot_variant p_var) + => (UInt16)(p_var.Type == Variant.Type.Int ? + p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var)); - public static unsafe UInt32 ConvertToUInt32(godot_variant* p_var) - => (UInt32)((*p_var)._type == Variant.Type.Int ? - (*p_var)._data._int : + public static UInt32 ConvertToUInt32(in godot_variant p_var) + => (UInt32)(p_var.Type == Variant.Type.Int ? + p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var)); - public static unsafe UInt64 ConvertToUInt64(godot_variant* p_var) - => (UInt64)((*p_var)._type == Variant.Type.Int ? - (*p_var)._data._int : + public static UInt64 ConvertToUInt64(in godot_variant p_var) + => (UInt64)(p_var.Type == Variant.Type.Int ? + p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var)); - public static unsafe float ConvertToFloat32(godot_variant* p_var) - => (float)((*p_var)._type == Variant.Type.Float ? - (*p_var)._data._float : + public static float ConvertToFloat32(in godot_variant p_var) + => (float)(p_var.Type == Variant.Type.Float ? + p_var.Float : NativeFuncs.godotsharp_variant_as_float(p_var)); - public static unsafe double ConvertToFloat64(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Float ? - (*p_var)._data._float : + public static double ConvertToFloat64(in godot_variant p_var) + => p_var.Type == Variant.Type.Float ? + p_var.Float : NativeFuncs.godotsharp_variant_as_float(p_var); - public static unsafe Vector2 ConvertToVector2(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Vector2 ? - (*p_var)._data._m_vector2 : + public static Vector2 ConvertToVector2(in godot_variant p_var) + => p_var.Type == Variant.Type.Vector2 ? + p_var.Vector2 : NativeFuncs.godotsharp_variant_as_vector2(p_var); - public static unsafe Vector2i ConvertToVector2i(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Vector2i ? - (*p_var)._data._m_vector2i : + public static Vector2i ConvertToVector2i(in godot_variant p_var) + => p_var.Type == Variant.Type.Vector2i ? + p_var.Vector2i : NativeFuncs.godotsharp_variant_as_vector2i(p_var); - public static unsafe Rect2 ConvertToRect2(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Rect2 ? - (*p_var)._data._m_rect2 : + public static Rect2 ConvertToRect2(in godot_variant p_var) + => p_var.Type == Variant.Type.Rect2 ? + p_var.Rect2 : NativeFuncs.godotsharp_variant_as_rect2(p_var); - public static unsafe Rect2i ConvertToRect2i(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Rect2i ? - (*p_var)._data._m_rect2i : + public static Rect2i ConvertToRect2i(in godot_variant p_var) + => p_var.Type == Variant.Type.Rect2i ? + p_var.Rect2i : NativeFuncs.godotsharp_variant_as_rect2i(p_var); - public static unsafe Transform2D ConvertToTransform2D(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Transform2d ? - *(*p_var)._data._transform2d : + public static unsafe Transform2D ConvertToTransform2D(in godot_variant p_var) + => p_var.Type == Variant.Type.Transform2d ? + *p_var.Transform2D : NativeFuncs.godotsharp_variant_as_transform2d(p_var); - public static unsafe Vector3 ConvertToVector3(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Vector3 ? - (*p_var)._data._m_vector3 : + public static Vector3 ConvertToVector3(in godot_variant p_var) + => p_var.Type == Variant.Type.Vector3 ? + p_var.Vector3 : NativeFuncs.godotsharp_variant_as_vector3(p_var); - public static unsafe Vector3i ConvertToVector3i(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Vector3i ? - (*p_var)._data._m_vector3i : + public static Vector3i ConvertToVector3i(in godot_variant p_var) + => p_var.Type == Variant.Type.Vector3i ? + p_var.Vector3i : NativeFuncs.godotsharp_variant_as_vector3i(p_var); - public static unsafe Vector4 ConvertToVector4(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Vector4 ? *(*p_var)._data._vector4 : NativeFuncs.godotsharp_variant_as_vector4(p_var); + public static unsafe Vector4 ConvertToVector4(in godot_variant p_var) + => p_var.Type == Variant.Type.Vector4 ? + *p_var.Vector4 : + NativeFuncs.godotsharp_variant_as_vector4(p_var); - public static unsafe Vector4i ConvertToVector4i(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Vector4i ? *(*p_var)._data._vector4i : NativeFuncs.godotsharp_variant_as_vector4i(p_var); + public static unsafe Vector4i ConvertToVector4i(in godot_variant p_var) + => p_var.Type == Variant.Type.Vector4i ? + *p_var.Vector4i : + NativeFuncs.godotsharp_variant_as_vector4i(p_var); - public static unsafe Basis ConvertToBasis(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Basis ? - *(*p_var)._data._basis : + public static unsafe Basis ConvertToBasis(in godot_variant p_var) + => p_var.Type == Variant.Type.Basis ? + *p_var.Basis : NativeFuncs.godotsharp_variant_as_basis(p_var); - public static unsafe Quaternion ConvertToQuaternion(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Quaternion ? - (*p_var)._data._m_quaternion : + public static Quaternion ConvertToQuaternion(in godot_variant p_var) + => p_var.Type == Variant.Type.Quaternion ? + p_var.Quaternion : NativeFuncs.godotsharp_variant_as_quaternion(p_var); - public static unsafe Transform3D ConvertToTransform3D(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Transform3d ? - *(*p_var)._data._transform3d : + public static unsafe Transform3D ConvertToTransform3D(in godot_variant p_var) + => p_var.Type == Variant.Type.Transform3d ? + *p_var.Transform3D : NativeFuncs.godotsharp_variant_as_transform3d(p_var); - public static unsafe Projection ConvertToProjection(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Projection ? *(*p_var)._data._projection : NativeFuncs.godotsharp_variant_as_projection(p_var); + public static unsafe Projection ConvertToProjection(in godot_variant p_var) + => p_var.Type == Variant.Type.Projection ? + *p_var.Projection : + NativeFuncs.godotsharp_variant_as_projection(p_var); - public static unsafe AABB ConvertToAABB(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Aabb ? - *(*p_var)._data._aabb : + public static unsafe AABB ConvertToAABB(in godot_variant p_var) + => p_var.Type == Variant.Type.Aabb ? + *p_var.AABB : NativeFuncs.godotsharp_variant_as_aabb(p_var); - public static unsafe Color ConvertToColor(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Color ? - (*p_var)._data._m_color : + public static Color ConvertToColor(in godot_variant p_var) + => p_var.Type == Variant.Type.Color ? + p_var.Color : NativeFuncs.godotsharp_variant_as_color(p_var); - public static unsafe Plane ConvertToPlane(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Plane ? - (*p_var)._data._m_plane : + public static Plane ConvertToPlane(in godot_variant p_var) + => p_var.Type == Variant.Type.Plane ? + p_var.Plane : NativeFuncs.godotsharp_variant_as_plane(p_var); - public static unsafe IntPtr ConvertToGodotObject(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Object ? (*p_var)._data._m_obj_data.obj : IntPtr.Zero; + public static IntPtr ConvertToGodotObject(in godot_variant p_var) + => p_var.Type == Variant.Type.Object ? p_var.Object : IntPtr.Zero; - public static unsafe RID ConvertToRID(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Rid ? - (*p_var)._data._m_rid : + public static RID ConvertToRID(in godot_variant p_var) + => p_var.Type == Variant.Type.Rid ? + p_var.RID : NativeFuncs.godotsharp_variant_as_rid(p_var); - public static unsafe godot_string_name ConvertToStringName(godot_variant* p_var) - => (*p_var)._type == Variant.Type.StringName ? - NativeFuncs.godotsharp_string_name_new_copy(&(*p_var)._data._m_string_name) : + public static godot_string_name ConvertToStringName(in godot_variant p_var) + => p_var.Type == Variant.Type.StringName ? + NativeFuncs.godotsharp_string_name_new_copy(p_var.StringName) : NativeFuncs.godotsharp_variant_as_string_name(p_var); - public static unsafe godot_node_path ConvertToNodePath(godot_variant* p_var) - => (*p_var)._type == Variant.Type.NodePath ? - NativeFuncs.godotsharp_node_path_new_copy(&(*p_var)._data._m_node_path) : + public static godot_node_path ConvertToNodePath(in godot_variant p_var) + => p_var.Type == Variant.Type.NodePath ? + NativeFuncs.godotsharp_node_path_new_copy(p_var.NodePath) : NativeFuncs.godotsharp_variant_as_node_path(p_var); - public static unsafe godot_array ConvertToArray(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Array ? - NativeFuncs.godotsharp_array_new_copy(&(*p_var)._data._m_array) : + public static godot_array ConvertToArray(in godot_variant p_var) + => p_var.Type == Variant.Type.Array ? + NativeFuncs.godotsharp_array_new_copy(p_var.Array) : NativeFuncs.godotsharp_variant_as_array(p_var); - public static unsafe godot_dictionary ConvertToDictionary(godot_variant* p_var) - => (*p_var)._type == Variant.Type.Dictionary ? - NativeFuncs.godotsharp_dictionary_new_copy(&(*p_var)._data._m_dictionary) : + public static godot_dictionary ConvertToDictionary(in godot_variant p_var) + => p_var.Type == Variant.Type.Dictionary ? + NativeFuncs.godotsharp_dictionary_new_copy(p_var.Dictionary) : NativeFuncs.godotsharp_variant_as_dictionary(p_var); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs index b18606b47e..d7b736fbcf 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.CompilerServices; using Godot.NativeInterop; namespace Godot @@ -42,7 +41,7 @@ namespace Godot /// </example> public sealed class NodePath : IDisposable { - public godot_node_path NativeValue; + internal godot_node_path.movable NativeValue; ~NodePath() { @@ -61,12 +60,12 @@ namespace Godot public void Dispose(bool disposing) { // Always dispose `NativeValue` even if disposing is true - NativeValue.Dispose(); + NativeValue.DangerousSelfRef.Dispose(); } private NodePath(godot_node_path nativeValueToOwn) { - NativeValue = nativeValueToOwn; + NativeValue = (godot_node_path.movable)nativeValueToOwn; } // Explicit name to make it very clear @@ -112,7 +111,7 @@ namespace Godot public NodePath(string path) { if (!string.IsNullOrEmpty(path)) - NativeValue = NativeFuncs.godotsharp_node_path_new_from_string(path); + NativeValue = (godot_node_path.movable)NativeFuncs.godotsharp_node_path_new_from_string(path); } /// <summary> @@ -125,22 +124,21 @@ namespace Godot /// Converts this <see cref="NodePath"/> to a string. /// </summary> /// <param name="from">The <see cref="NodePath"/> to convert.</param> - public static implicit operator string(NodePath from) => from.ToString(); + public static implicit operator string(NodePath from) => from?.ToString(); /// <summary> /// Converts this <see cref="NodePath"/> to a string. /// </summary> /// <returns>A string representation of this <see cref="NodePath"/>.</returns> - public override unsafe string ToString() + public override string ToString() { if (IsEmpty) return string.Empty; - godot_string dest; - godot_node_path src = NativeValue; - NativeFuncs.godotsharp_node_path_as_string(&dest, &src); + var src = (godot_node_path)NativeValue; + NativeFuncs.godotsharp_node_path_as_string(out godot_string dest, src); using (dest) - return Marshaling.mono_string_from_godot(dest); + return Marshaling.ConvertStringToManaged(dest); } /// <summary> @@ -161,7 +159,8 @@ namespace Godot public NodePath GetAsPropertyPath() { godot_node_path propertyPath = default; - NativeFuncs.godotsharp_node_path_get_as_property_path(ref NativeValue, ref propertyPath); + var self = (godot_node_path)NativeValue; + NativeFuncs.godotsharp_node_path_get_as_property_path(self, ref propertyPath); return CreateTakingOwnershipOfDisposableValue(propertyPath); } @@ -175,11 +174,12 @@ namespace Godot /// </code> /// </example> /// <returns>The names concatenated with <c>/</c>.</returns> - public unsafe string GetConcatenatedNames() + public string GetConcatenatedNames() { - using godot_string names = default; - NativeFuncs.godotsharp_node_path_get_concatenated_names(ref NativeValue, &names); - return Marshaling.mono_string_from_godot(names); + var self = (godot_node_path)NativeValue; + NativeFuncs.godotsharp_node_path_get_concatenated_names(self, out godot_string names); + using (names) + return Marshaling.ConvertStringToManaged(names); } /// <summary> @@ -193,11 +193,12 @@ namespace Godot /// </code> /// </example> /// <returns>The subnames concatenated with <c>:</c>.</returns> - public unsafe string GetConcatenatedSubNames() + public string GetConcatenatedSubNames() { - using godot_string subNames = default; - NativeFuncs.godotsharp_node_path_get_concatenated_subnames(ref NativeValue, &subNames); - return Marshaling.mono_string_from_godot(subNames); + var self = (godot_node_path)NativeValue; + NativeFuncs.godotsharp_node_path_get_concatenated_subnames(self, out godot_string subNames); + using (subNames) + return Marshaling.ConvertStringToManaged(subNames); } /// <summary> @@ -213,11 +214,12 @@ namespace Godot /// </example> /// <param name="idx">The name index.</param> /// <returns>The name at the given index <paramref name="idx"/>.</returns> - public unsafe string GetName(int idx) + public string GetName(int idx) { - using godot_string name = default; - NativeFuncs.godotsharp_node_path_get_name(ref NativeValue, idx, &name); - return Marshaling.mono_string_from_godot(name); + var self = (godot_node_path)NativeValue; + NativeFuncs.godotsharp_node_path_get_name(self, idx, out godot_string name); + using (name) + return Marshaling.ConvertStringToManaged(name); } /// <summary> @@ -228,7 +230,8 @@ namespace Godot /// <returns>The number of node names which make up the path.</returns> public int GetNameCount() { - return NativeFuncs.godotsharp_node_path_get_name_count(ref NativeValue); + var self = (godot_node_path)NativeValue; + return NativeFuncs.godotsharp_node_path_get_name_count(self); } /// <summary> @@ -236,11 +239,12 @@ namespace Godot /// </summary> /// <param name="idx">The subname index.</param> /// <returns>The subname at the given index <paramref name="idx"/>.</returns> - public unsafe string GetSubName(int idx) + public string GetSubName(int idx) { - using godot_string subName = default; - NativeFuncs.godotsharp_node_path_get_subname(ref NativeValue, idx, &subName); - return Marshaling.mono_string_from_godot(subName); + var self = (godot_node_path)NativeValue; + NativeFuncs.godotsharp_node_path_get_subname(self, idx, out godot_string subName); + using (subName) + return Marshaling.ConvertStringToManaged(subName); } /// <summary> @@ -251,7 +255,8 @@ namespace Godot /// <returns>The number of subnames in the path.</returns> public int GetSubNameCount() { - return NativeFuncs.godotsharp_node_path_get_subname_count(ref NativeValue); + var self = (godot_node_path)NativeValue; + return NativeFuncs.godotsharp_node_path_get_subname_count(self); } /// <summary> @@ -263,13 +268,14 @@ namespace Godot /// <returns>If the <see cref="NodePath"/> is an absolute path.</returns> public bool IsAbsolute() { - return NativeFuncs.godotsharp_node_path_is_absolute(ref NativeValue).ToBool(); + var self = (godot_node_path)NativeValue; + return NativeFuncs.godotsharp_node_path_is_absolute(self).ToBool(); } /// <summary> /// Returns <see langword="true"/> if the node path is empty. /// </summary> /// <returns>If the <see cref="NodePath"/> is empty.</returns> - public bool IsEmpty => godot_node_path.IsEmpty(in NativeValue); + public bool IsEmpty => NativeValue.DangerousSelfRef.IsEmpty; } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs index 98266ffdfc..5f4dc50c72 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs @@ -1,7 +1,6 @@ using System; using System.Linq; using System.Reflection; -using System.Runtime.CompilerServices; using Godot.NativeInterop; namespace Godot @@ -47,16 +46,13 @@ namespace Godot while (top != null && top != native) { foreach (var eventSignal in top.GetEvents( - BindingFlags.DeclaredOnly | BindingFlags.Instance | - BindingFlags.NonPublic | BindingFlags.Public) - .Where(ev => ev.GetCustomAttributes().OfType<SignalAttribute>().Any())) + BindingFlags.DeclaredOnly | BindingFlags.Instance | + BindingFlags.NonPublic | BindingFlags.Public) + .Where(ev => ev.GetCustomAttributes().OfType<SignalAttribute>().Any())) { - unsafe - { - using var eventSignalName = new StringName(eventSignal.Name); - godot_string_name eventSignalNameAux = eventSignalName.NativeValue; - NativeFuncs.godotsharp_internal_object_connect_event_signal(NativePtr, &eventSignalNameAux); - } + using var eventSignalName = new StringName(eventSignal.Name); + var eventSignalNameSelf = (godot_string_name)eventSignalName.NativeValue; + NativeFuncs.godotsharp_internal_object_connect_event_signal(NativePtr, eventSignalNameSelf); } top = top.BaseType; @@ -128,11 +124,11 @@ namespace Godot /// Converts this <see cref="Object"/> to a string. /// </summary> /// <returns>A string representation of this object.</returns> - public override unsafe string ToString() + public override string ToString() { - using godot_string str = default; - NativeFuncs.godotsharp_object_to_string(GetPtr(this), &str); - return Marshaling.mono_string_from_godot(str); + NativeFuncs.godotsharp_object_to_string(GetPtr(this), out godot_string str); + using (str) + return Marshaling.ConvertStringToManaged(str); } /// <summary> @@ -189,7 +185,7 @@ namespace Godot return assemblyName.Name == "GodotSharp" || assemblyName.Name == "GodotSharpEditor"; } - internal unsafe bool InternalGodotScriptCallViaReflection(string method, godot_variant** args, int argCount, + internal bool InternalGodotScriptCallViaReflection(string method, NativeVariantPtrArgs args, int argCount, out godot_variant ret) { // Performance is not critical here as this will be replaced with source generators. @@ -213,13 +209,13 @@ namespace Godot for (int i = 0; i < paramCount; i++) { - invokeParams[i] = Marshaling.variant_to_mono_object_of_type( + invokeParams[i] = Marshaling.ConvertVariantToManagedObjectOfType( args[i], parameters[i].ParameterType); } object retObj = methodInfo.Invoke(this, invokeParams); - ret = Marshaling.mono_object_to_variant(retObj); + ret = Marshaling.ConvertManagedObjectToVariant(retObj); return true; } } @@ -231,7 +227,7 @@ namespace Godot return false; } - internal unsafe bool InternalGodotScriptSetFieldOrPropViaReflection(string name, godot_variant* value) + internal bool InternalGodotScriptSetFieldOrPropViaReflection(string name, in godot_variant value) { // Performance is not critical here as this will be replaced with source generators. Type top = GetType(); @@ -245,7 +241,7 @@ namespace Godot if (fieldInfo != null) { - object valueManaged = Marshaling.variant_to_mono_object_of_type(value, fieldInfo.FieldType); + object valueManaged = Marshaling.ConvertVariantToManagedObjectOfType(value, fieldInfo.FieldType); fieldInfo.SetValue(this, valueManaged); return true; @@ -257,7 +253,8 @@ namespace Godot if (propertyInfo != null) { - object valueManaged = Marshaling.variant_to_mono_object_of_type(value, propertyInfo.PropertyType); + object valueManaged = + Marshaling.ConvertVariantToManagedObjectOfType(value, propertyInfo.PropertyType); propertyInfo.SetValue(this, valueManaged); return true; @@ -284,7 +281,7 @@ namespace Godot if (fieldInfo != null) { object valueManaged = fieldInfo.GetValue(this); - value = Marshaling.mono_object_to_variant(valueManaged); + value = Marshaling.ConvertManagedObjectToVariant(valueManaged); return true; } @@ -295,7 +292,7 @@ namespace Godot if (propertyInfo != null) { object valueManaged = propertyInfo.GetValue(this); - value = Marshaling.mono_object_to_variant(valueManaged); + value = Marshaling.ConvertManagedObjectToVariant(valueManaged); return true; } @@ -306,7 +303,7 @@ namespace Godot return false; } - internal unsafe void InternalRaiseEventSignal(godot_string_name* eventSignalName, godot_variant** args, + internal unsafe void InternalRaiseEventSignal(in godot_string_name eventSignalName, NativeVariantPtrArgs args, int argc) { // Performance is not critical here as this will be replaced with source generators. @@ -360,9 +357,9 @@ namespace Godot var managedArgs = new object[argc]; - for (uint i = 0; i < argc; i++) + for (int i = 0; i < argc; i++) { - managedArgs[i] = Marshaling.variant_to_mono_object_of_type( + managedArgs[i] = Marshaling.ConvertVariantToManagedObjectOfType( args[i], parameterInfos[i].ParameterType); } @@ -379,7 +376,8 @@ namespace Godot IntPtr methodBind; fixed (char* methodChars = method) { - methodBind = NativeFuncs.godotsharp_method_bind_get_method(ref type.NativeValue, methodChars); + var typeSelf = (godot_string_name)type.NativeValue; + methodBind = NativeFuncs.godotsharp_method_bind_get_method(typeSelf, methodChars); } if (methodBind == IntPtr.Zero) @@ -391,7 +389,8 @@ namespace Godot internal static unsafe delegate* unmanaged<IntPtr> ClassDB_get_constructor(StringName type) { // for some reason the '??' operator doesn't support 'delegate*' - var nativeConstructor = NativeFuncs.godotsharp_get_class_constructor(ref type.NativeValue); + var typeSelf = (godot_string_name)type.NativeValue; + var nativeConstructor = NativeFuncs.godotsharp_get_class_constructor(typeSelf); if (nativeConstructor == null) throw new NativeConstructorNotFoundException(type); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs index e38dca414f..369b95c7cb 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs @@ -73,7 +73,7 @@ namespace Godot case 3: return w; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } set @@ -93,7 +93,7 @@ namespace Godot w = value; break; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs index 62dec81582..c8bf686afa 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs @@ -8,19 +8,21 @@ namespace Godot { private bool _completed; private object[] _result; - private Action _action; + private Action _continuation; public SignalAwaiter(Object source, StringName signal, Object target) { - NativeFuncs.godotsharp_internal_signal_awaiter_connect(Object.GetPtr(source), ref signal.NativeValue, + using godot_string_name signalSrc = NativeFuncs.godotsharp_string_name_new_copy( + (godot_string_name)(signal?.NativeValue ?? default)); + NativeFuncs.godotsharp_internal_signal_awaiter_connect(Object.GetPtr(source), in signalSrc, Object.GetPtr(target), GCHandle.ToIntPtr(GCHandle.Alloc(this))); } public bool IsCompleted => _completed; - public void OnCompleted(Action action) + public void OnCompleted(Action continuation) { - this._action = action; + _continuation = continuation; } public object[] GetResult() => _result; @@ -48,11 +50,11 @@ namespace Godot object[] signalArgs = new object[argCount]; for (int i = 0; i < argCount; i++) - signalArgs[i] = Marshaling.variant_to_mono_object(args[i]); + signalArgs[i] = Marshaling.ConvertVariantToManagedObject(*args[i]); awaiter._result = signalArgs; - awaiter._action?.Invoke(); + awaiter._continuation?.Invoke(); } catch (Exception e) { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs index da01300586..3f50df0a0d 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs @@ -3,7 +3,7 @@ namespace Godot /// <summary> /// Represents a signal defined in an object. /// </summary> - public struct SignalInfo + public readonly struct SignalInfo { private readonly Object _owner; private readonly StringName _signalName; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs index dfdef81f9e..ce89e134b8 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs @@ -1,12 +1,13 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.Runtime.CompilerServices; using System.Security; using System.Text; using System.Text.RegularExpressions; using Godot.NativeInterop; +#nullable enable + namespace Godot { /// <summary> @@ -1077,12 +1078,12 @@ namespace Godot /// <seealso cref="MD5Text(string)"/> /// <param name="instance">The string to hash.</param> /// <returns>The MD5 hash of the string.</returns> - public static unsafe byte[] MD5Buffer(this string instance) + public static byte[] MD5Buffer(this string instance) { - using godot_string instanceStr = Marshaling.mono_string_to_godot(instance); - using godot_packed_byte_array md5Buffer = default; - NativeFuncs.godotsharp_string_md5_buffer(&instanceStr, &md5Buffer); - return Marshaling.PackedByteArray_to_mono_array(&md5Buffer); + using godot_string instanceStr = Marshaling.ConvertStringToNative(instance); + NativeFuncs.godotsharp_string_md5_buffer(instanceStr, out var md5Buffer); + using (md5Buffer) + return Marshaling.ConvertNativePackedByteArrayToSystemArray(md5Buffer); } /// <summary> @@ -1091,12 +1092,12 @@ namespace Godot /// <seealso cref="MD5Buffer(string)"/> /// <param name="instance">The string to hash.</param> /// <returns>The MD5 hash of the string.</returns> - public static unsafe string MD5Text(this string instance) + public static string MD5Text(this string instance) { - using godot_string instanceStr = Marshaling.mono_string_to_godot(instance); - using godot_string md5Text = default; - NativeFuncs.godotsharp_string_md5_text(&instanceStr, &md5Text); - return Marshaling.mono_string_from_godot(md5Text); + using godot_string instanceStr = Marshaling.ConvertStringToNative(instance); + NativeFuncs.godotsharp_string_md5_text(instanceStr, out var md5Text); + using (md5Text) + return Marshaling.ConvertStringToManaged(md5Text); } /// <summary> @@ -1251,11 +1252,11 @@ namespace Godot /// <param name="what">The substring to search in the string.</param> /// <param name="from">The position at which to start searching.</param> /// <returns>The position at which the substring was found, or -1 if not found.</returns> - public static unsafe int RFind(this string instance, string what, int from = -1) + public static int RFind(this string instance, string what, int from = -1) { - using godot_string instanceStr = Marshaling.mono_string_to_godot(instance); - using godot_string whatStr = Marshaling.mono_string_to_godot(instance); - return NativeFuncs.godotsharp_string_rfind(&instanceStr, &whatStr, from); + using godot_string instanceStr = Marshaling.ConvertStringToNative(instance); + using godot_string whatStr = Marshaling.ConvertStringToNative(instance); + return NativeFuncs.godotsharp_string_rfind(instanceStr, whatStr, from); } /// <summary> @@ -1267,11 +1268,11 @@ namespace Godot /// <param name="what">The substring to search in the string.</param> /// <param name="from">The position at which to start searching.</param> /// <returns>The position at which the substring was found, or -1 if not found.</returns> - public static unsafe int RFindN(this string instance, string what, int from = -1) + public static int RFindN(this string instance, string what, int from = -1) { - using godot_string instanceStr = Marshaling.mono_string_to_godot(instance); - using godot_string whatStr = Marshaling.mono_string_to_godot(instance); - return NativeFuncs.godotsharp_string_rfindn(&instanceStr, &whatStr, from); + using godot_string instanceStr = Marshaling.ConvertStringToNative(instance); + using godot_string whatStr = Marshaling.ConvertStringToNative(instance); + return NativeFuncs.godotsharp_string_rfindn(instanceStr, whatStr, from); } /// <summary> @@ -1326,12 +1327,12 @@ namespace Godot /// <seealso cref="SHA256Text(string)"/> /// <param name="instance">The string to hash.</param> /// <returns>The SHA-256 hash of the string.</returns> - public static unsafe byte[] SHA256Buffer(this string instance) + public static byte[] SHA256Buffer(this string instance) { - using godot_string instanceStr = Marshaling.mono_string_to_godot(instance); - using godot_packed_byte_array sha256Buffer = default; - NativeFuncs.godotsharp_string_sha256_buffer(&instanceStr, &sha256Buffer); - return Marshaling.PackedByteArray_to_mono_array(&sha256Buffer); + using godot_string instanceStr = Marshaling.ConvertStringToNative(instance); + NativeFuncs.godotsharp_string_sha256_buffer(instanceStr, out var sha256Buffer); + using (sha256Buffer) + return Marshaling.ConvertNativePackedByteArrayToSystemArray(sha256Buffer); } /// <summary> @@ -1340,12 +1341,12 @@ namespace Godot /// <seealso cref="SHA256Buffer(string)"/> /// <param name="instance">The string to hash.</param> /// <returns>The SHA-256 hash of the string.</returns> - public static unsafe string SHA256Text(this string instance) + public static string SHA256Text(this string instance) { - using godot_string instanceStr = Marshaling.mono_string_to_godot(instance); - using godot_string sha256Text = default; - NativeFuncs.godotsharp_string_sha256_text(&instanceStr, &sha256Text); - return Marshaling.mono_string_from_godot(sha256Text); + using godot_string instanceStr = Marshaling.ConvertStringToNative(instance); + NativeFuncs.godotsharp_string_sha256_text(instanceStr, out var sha256Text); + using (sha256Text) + return Marshaling.ConvertStringToManaged(sha256Text); } /// <summary> @@ -1396,12 +1397,12 @@ namespace Godot /// <summary> /// Returns a simplified canonical path. /// </summary> - public static unsafe string SimplifyPath(this string instance) + public static string SimplifyPath(this string instance) { - using godot_string instanceStr = Marshaling.mono_string_to_godot(instance); - using godot_string simplifiedPath = default; - NativeFuncs.godotsharp_string_simplify_path(&instanceStr, &simplifiedPath); - return Marshaling.mono_string_from_godot(simplifiedPath); + using godot_string instanceStr = Marshaling.ConvertStringToNative(instance); + NativeFuncs.godotsharp_string_simplify_path(instanceStr, out godot_string simplifiedPath); + using (simplifiedPath) + return Marshaling.ConvertStringToManaged(simplifiedPath); } /// <summary> @@ -1602,7 +1603,7 @@ namespace Godot /// <seealso cref="XMLUnescape(string)"/> /// <param name="instance">The string to escape.</param> /// <returns>The escaped string.</returns> - public static string XMLEscape(this string instance) + public static string? XMLEscape(this string instance) { return SecurityElement.Escape(instance); } @@ -1614,9 +1615,9 @@ namespace Godot /// <seealso cref="XMLEscape(string)"/> /// <param name="instance">The string to unescape.</param> /// <returns>The unescaped string.</returns> - public static string XMLUnescape(this string instance) + public static string? XMLUnescape(this string instance) { - return SecurityElement.FromString(instance).Text; + return SecurityElement.FromString(instance)?.Text; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs index 84b0ab623c..e8bda9b219 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.CompilerServices; using Godot.NativeInterop; namespace Godot @@ -13,7 +12,7 @@ namespace Godot /// </summary> public sealed class StringName : IDisposable { - public godot_string_name NativeValue; + internal godot_string_name.movable NativeValue; ~StringName() { @@ -32,12 +31,12 @@ namespace Godot public void Dispose(bool disposing) { // Always dispose `NativeValue` even if disposing is true - NativeValue.Dispose(); + NativeValue.DangerousSelfRef.Dispose(); } private StringName(godot_string_name nativeValueToOwn) { - NativeValue = nativeValueToOwn; + NativeValue = (godot_string_name.movable)nativeValueToOwn; } // Explicit name to make it very clear @@ -58,7 +57,7 @@ namespace Godot public StringName(string name) { if (!string.IsNullOrEmpty(name)) - NativeValue = NativeFuncs.godotsharp_string_name_new_from_string(name); + NativeValue = (godot_string_name.movable)NativeFuncs.godotsharp_string_name_new_from_string(name); } /// <summary> @@ -71,28 +70,27 @@ namespace Godot /// Converts a <see cref="StringName"/> to a string. /// </summary> /// <param name="from">The <see cref="StringName"/> to convert.</param> - public static implicit operator string(StringName from) => from.ToString(); + public static implicit operator string(StringName from) => from?.ToString(); /// <summary> /// Converts this <see cref="StringName"/> to a string. /// </summary> /// <returns>A string representation of this <see cref="StringName"/>.</returns> - public override unsafe string ToString() + public override string ToString() { if (IsEmpty) return string.Empty; - godot_string dest; - godot_string_name src = NativeValue; - NativeFuncs.godotsharp_string_name_as_string(&dest, &src); + var src = (godot_string_name)NativeValue; + NativeFuncs.godotsharp_string_name_as_string(out godot_string dest, src); using (dest) - return Marshaling.mono_string_from_godot(dest); + return Marshaling.ConvertStringToManaged(dest); } /// <summary> /// Check whether this <see cref="StringName"/> is empty. /// </summary> /// <returns>If the <see cref="StringName"/> is empty.</returns> - public bool IsEmpty => godot_string_name.IsEmpty(in NativeValue); + public bool IsEmpty => NativeValue.DangerousSelfRef.IsEmpty; } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs index 68d097eb4e..1e3a13ba8e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs @@ -93,7 +93,7 @@ namespace Godot case 2: return origin; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(column)); } } set @@ -110,7 +110,7 @@ namespace Godot origin = value; return; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(column)); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs index 9eaf4f3252..27de87d7d4 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs @@ -52,7 +52,7 @@ namespace Godot case 3: return origin; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(column)); } } set @@ -72,7 +72,7 @@ namespace Godot origin = value; return; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(column)); } } } @@ -168,7 +168,7 @@ namespace Godot /// <param name="target">The object to look at.</param> /// <param name="up">The relative up direction.</param> /// <returns>The resulting transform.</returns> - public Transform3D LookingAt(Vector3 target, Vector3 up) + public readonly Transform3D LookingAt(Vector3 target, Vector3 up) { Transform3D t = this; t.SetLookAt(origin, target, up); @@ -194,7 +194,7 @@ namespace Godot /// <param name="axis">The axis to rotate around. Must be normalized.</param> /// <param name="angle">The angle to rotate, in radians.</param> /// <returns>The rotated transformation matrix.</returns> - public Transform3D Rotated(Vector3 axis, real_t angle) + public readonly Transform3D Rotated(Vector3 axis, real_t angle) { return new Transform3D(new Basis(axis, angle), new Vector3()) * this; } @@ -443,7 +443,7 @@ namespace Godot /// </summary> /// <param name="obj">The object to compare with.</param> /// <returns>Whether or not the transform and the object are exactly equal.</returns> - public override bool Equals(object obj) + public override readonly bool Equals(object obj) { if (obj is Transform3D) { @@ -460,7 +460,7 @@ namespace Godot /// </summary> /// <param name="other">The other transform to compare.</param> /// <returns>Whether or not the matrices are exactly equal.</returns> - public bool Equals(Transform3D other) + public readonly bool Equals(Transform3D other) { return basis.Equals(other.basis) && origin.Equals(other.origin); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs index 67f70390dd..6223f3ae53 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs @@ -62,7 +62,7 @@ namespace Godot case 1: return y; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } set @@ -76,7 +76,7 @@ namespace Godot y = value; return; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs index b61954a84c..e4c3f869b1 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs @@ -62,7 +62,7 @@ namespace Godot case 1: return y; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } set @@ -76,7 +76,7 @@ namespace Godot y = value; return; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs index 67a98efc2d..7e98969d34 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs @@ -74,7 +74,7 @@ namespace Godot case 2: return z; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } set @@ -91,7 +91,7 @@ namespace Godot z = value; return; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs index 0d4894f206..88b58e20cd 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs @@ -74,7 +74,7 @@ namespace Godot case 2: return z; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } set @@ -91,7 +91,7 @@ namespace Godot z = value; return; default: - throw new IndexOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(index)); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/FodyWeavers.xml b/modules/mono/glue/GodotSharp/GodotSharp/FodyWeavers.xml new file mode 100644 index 0000000000..d7abb3c982 --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/FodyWeavers.xml @@ -0,0 +1,3 @@ +<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> + <InlineIL /> +</Weavers> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GenerateGodotCustomUnsafe.targets b/modules/mono/glue/GodotSharp/GodotSharp/GenerateGodotCustomUnsafe.targets new file mode 100644 index 0000000000..f572f8a75c --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/GenerateGodotCustomUnsafe.targets @@ -0,0 +1,93 @@ +<Project> + <!-- Generate Godot.NativeInterop.CustomUnsafe C# class--> + + <!-- + Ref structs are not allowed as generic type parameters, so we can't use Unsafe.AsPointer<T>/AsRef<T>. + As a workaround we generate overloads of those methods for our structs using Fody with inline IL. + --> + + <ItemGroup> + <PackageReference Include="Fody" Version="6.6.0" PrivateAssets="all" /> + <PackageReference Include="InlineIL.Fody" Version="1.7.1" PrivateAssets="all" /> + </ItemGroup> + + <ItemGroup> + <GodotInteropStructs Include="godot_ref" /> + <GodotInteropStructs Include="godot_variant_call_error" /> + <GodotInteropStructs Include="godot_variant" /> + <GodotInteropStructs Include="godot_string" /> + <GodotInteropStructs Include="godot_string_name" /> + <GodotInteropStructs Include="godot_node_path" /> + <GodotInteropStructs Include="godot_signal" /> + <GodotInteropStructs Include="godot_callable" /> + <GodotInteropStructs Include="godot_array" /> + <GodotInteropStructs Include="godot_dictionary" /> + <GodotInteropStructs Include="godot_packed_byte_array" /> + <GodotInteropStructs Include="godot_packed_int32_array" /> + <GodotInteropStructs Include="godot_packed_int64_array" /> + <GodotInteropStructs Include="godot_packed_float32_array" /> + <GodotInteropStructs Include="godot_packed_float64_array" /> + <GodotInteropStructs Include="godot_packed_string_array" /> + <GodotInteropStructs Include="godot_packed_vector2_array" /> + <GodotInteropStructs Include="godot_packed_vector3_array" /> + <GodotInteropStructs Include="godot_packed_color_array" /> + </ItemGroup> + + <Target Name="GenerateGodotCustomUnsafe" + DependsOnTargets="_GenerateGodotCustomUnsafe" + BeforeTargets="PrepareForBuild;CompileDesignTime;BeforeCompile;CoreCompile"> + <ItemGroup> + <Compile Include="$(IntermediateOutputPath)CustomUnsafe.%(GodotInteropStructs.Identity).g.cs" /> + <FileWrites Include="$(IntermediateOutputPath)CustomUnsafe.%(GodotInteropStructs.Identity).g.cs" /> + </ItemGroup> + </Target> + <Target Name="_GenerateGodotCustomUnsafe" + Inputs="$(MSBuildProjectFile);$(MSBuildThisFileDirectory);@(GodotInteropStructs)" + Outputs="$(IntermediateOutputPath)CustomUnsafe.%(GodotInteropStructs.Identity).g.cs"> + <PropertyGroup> + <GodotInteropStruct>%(GodotInteropStructs.Identity)</GodotInteropStruct> + <GenerateGodotCustomUnsafeCode><![CDATA[ +using System.Runtime.CompilerServices%3b +using InlineIL%3b +using static InlineIL.IL.Emit%3b + +namespace Godot.NativeInterop +{ + public static partial class CustomUnsafe + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe $(GodotInteropStruct)* AsPointer(ref $(GodotInteropStruct) value) + { + Ldarg(nameof(value))%3b + Conv_U()%3b + return ($(GodotInteropStruct)*)IL.ReturnPointer()%3b + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static unsafe $(GodotInteropStruct)* ReadOnlyRefAsPointer(in $(GodotInteropStruct) value) + { + Ldarg(nameof(value))%3b + Conv_U()%3b + return ($(GodotInteropStruct)*)IL.ReturnPointer()%3b + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe ref $(GodotInteropStruct) AsRef($(GodotInteropStruct)* source) + { + return ref *source%3b + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe ref $(GodotInteropStruct) AsRef(in $(GodotInteropStruct) source) + { + return ref *ReadOnlyRefAsPointer(in source)%3b + } + } +} +]]></GenerateGodotCustomUnsafeCode> + </PropertyGroup> + <WriteLinesToFile Lines="$(GenerateGodotCustomUnsafeCode)" + File="$(IntermediateOutputPath)CustomUnsafe.%(GodotInteropStructs.Identity).g.cs" + Overwrite="True" WriteOnlyWhenDifferent="True" /> + </Target> +</Project> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj index 763ded8809..a06b448136 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj +++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj @@ -10,6 +10,8 @@ <AllowUnsafeBlocks>true</AllowUnsafeBlocks> <LangVersion>9</LangVersion> + <AnalysisMode>Recommended</AnalysisMode> + <!-- Disabled temporarily as it pollutes the warnings, but we need to document public APIs. --> <NoWarn>CS1591</NoWarn> </PropertyGroup> @@ -20,6 +22,12 @@ <PackageReference Include="ReflectionAnalyzers" Version="0.1.22-dev" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers" /> <!--PackageReference Include="IDisposableAnalyzers" Version="3.4.13" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers" /--> </ItemGroup> + <!-- Targets for generating Godot.NativeInterop.CustomUnsafe --> + <Import Project="GenerateGodotCustomUnsafe.targets" /> + <ItemGroup> + <None Include="GenerateGodotCustomUnsafe.targets" /> + </ItemGroup> + <!-- Sources --> <ItemGroup> <Compile Include="Core\AABB.cs" /> <Compile Include="Core\Array.cs" /> @@ -62,6 +70,7 @@ <Compile Include="Core\NativeInterop\ExceptionUtils.cs" /> <Compile Include="Core\NativeInterop\InteropUtils.cs" /> <Compile Include="Core\NativeInterop\NativeFuncs.extended.cs" /> + <Compile Include="Core\NativeInterop\NativeVariantPtrArgs.cs" /> <Compile Include="Core\NativeInterop\VariantSpanHelpers.cs" /> <Compile Include="Core\NativeInterop\VariantUtils.cs" /> <Compile Include="Core\NodePath.cs" /> |