C#: Revert marshalling of IDictionary/IEnumerable implementing types
Added marshalling for `System.Collections.Generic.List<T>` and `System.Collections.Generic.Dictionary<TKey, TValue>`.
This commit is contained in:
parent
ed27b7e6b9
commit
6aca932659
|
@ -15,10 +15,7 @@ namespace Godot.Collections
|
||||||
|
|
||||||
public override bool IsInvalid
|
public override bool IsInvalid
|
||||||
{
|
{
|
||||||
get
|
get { return handle == IntPtr.Zero; }
|
||||||
{
|
|
||||||
return handle == IntPtr.Zero;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool ReleaseHandle()
|
protected override bool ReleaseHandle()
|
||||||
|
@ -43,7 +40,8 @@ namespace Godot.Collections
|
||||||
if (collection == null)
|
if (collection == null)
|
||||||
throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'");
|
throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'");
|
||||||
|
|
||||||
MarshalUtils.EnumerableToArray(collection, GetPtr());
|
foreach (object element in collection)
|
||||||
|
Add(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Array(ArraySafeHandle handle)
|
internal Array(ArraySafeHandle handle)
|
||||||
|
@ -272,14 +270,8 @@ namespace Godot.Collections
|
||||||
|
|
||||||
public T this[int index]
|
public T this[int index]
|
||||||
{
|
{
|
||||||
get
|
get { return (T)Array.godot_icall_Array_At_Generic(GetPtr(), index, elemTypeEncoding, elemTypeClass); }
|
||||||
{
|
set { objectArray[index] = value; }
|
||||||
return (T)Array.godot_icall_Array_At_Generic(GetPtr(), index, elemTypeEncoding, elemTypeClass);
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
objectArray[index] = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int IndexOf(T item)
|
public int IndexOf(T item)
|
||||||
|
@ -301,18 +293,12 @@ namespace Godot.Collections
|
||||||
|
|
||||||
public int Count
|
public int Count
|
||||||
{
|
{
|
||||||
get
|
get { return objectArray.Count; }
|
||||||
{
|
|
||||||
return objectArray.Count;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsReadOnly
|
public bool IsReadOnly
|
||||||
{
|
{
|
||||||
get
|
get { return objectArray.IsReadOnly; }
|
||||||
{
|
|
||||||
return objectArray.IsReadOnly;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(T item)
|
public void Add(T item)
|
||||||
|
|
|
@ -15,10 +15,7 @@ namespace Godot.Collections
|
||||||
|
|
||||||
public override bool IsInvalid
|
public override bool IsInvalid
|
||||||
{
|
{
|
||||||
get
|
get { return handle == IntPtr.Zero; }
|
||||||
{
|
|
||||||
return handle == IntPtr.Zero;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool ReleaseHandle()
|
protected override bool ReleaseHandle()
|
||||||
|
@ -45,7 +42,8 @@ namespace Godot.Collections
|
||||||
if (dictionary == null)
|
if (dictionary == null)
|
||||||
throw new NullReferenceException($"Parameter '{nameof(dictionary)} cannot be null.'");
|
throw new NullReferenceException($"Parameter '{nameof(dictionary)} cannot be null.'");
|
||||||
|
|
||||||
MarshalUtils.IDictionaryToDictionary(dictionary, GetPtr());
|
foreach (DictionaryEntry entry in dictionary)
|
||||||
|
Add(entry.Key, entry.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Dictionary(DictionarySafeHandle handle)
|
internal Dictionary(DictionarySafeHandle handle)
|
||||||
|
@ -330,14 +328,8 @@ namespace Godot.Collections
|
||||||
|
|
||||||
public TValue this[TKey key]
|
public TValue this[TKey key]
|
||||||
{
|
{
|
||||||
get
|
get { return (TValue)Dictionary.godot_icall_Dictionary_GetValue_Generic(objectDict.GetPtr(), key, valTypeEncoding, valTypeClass); }
|
||||||
{
|
set { objectDict[key] = value; }
|
||||||
return (TValue)Dictionary.godot_icall_Dictionary_GetValue_Generic(objectDict.GetPtr(), key, valTypeEncoding, valTypeClass);
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
objectDict[key] = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ICollection<TKey> Keys
|
public ICollection<TKey> Keys
|
||||||
|
@ -385,18 +377,12 @@ namespace Godot.Collections
|
||||||
|
|
||||||
public int Count
|
public int Count
|
||||||
{
|
{
|
||||||
get
|
get { return objectDict.Count; }
|
||||||
{
|
|
||||||
return objectDict.Count;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsReadOnly
|
public bool IsReadOnly
|
||||||
{
|
{
|
||||||
get
|
get { return objectDict.IsReadOnly; }
|
||||||
{
|
|
||||||
return objectDict.IsReadOnly;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(KeyValuePair<TKey, TValue> item)
|
public void Add(KeyValuePair<TKey, TValue> item)
|
||||||
|
@ -440,7 +426,8 @@ namespace Godot.Collections
|
||||||
|
|
||||||
public bool Remove(KeyValuePair<TKey, TValue> item)
|
public bool Remove(KeyValuePair<TKey, TValue> item)
|
||||||
{
|
{
|
||||||
return Dictionary.godot_icall_Dictionary_Remove(GetPtr(), item.Key, item.Value); ;
|
return Dictionary.godot_icall_Dictionary_Remove(GetPtr(), item.Key, item.Value);
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
// IEnumerable<KeyValuePair<TKey, TValue>>
|
// IEnumerable<KeyValuePair<TKey, TValue>>
|
||||||
|
|
|
@ -16,10 +16,8 @@ namespace Godot
|
||||||
/// <exception cref="System.InvalidOperationException">
|
/// <exception cref="System.InvalidOperationException">
|
||||||
/// <paramref name="type"/> is not a generic type. That is, IsGenericType returns false.
|
/// <paramref name="type"/> is not a generic type. That is, IsGenericType returns false.
|
||||||
/// </exception>
|
/// </exception>
|
||||||
static bool TypeIsGenericArray(Type type)
|
static bool TypeIsGenericArray(Type type) =>
|
||||||
{
|
type.GetGenericTypeDefinition() == typeof(Godot.Collections.Array<>);
|
||||||
return type.GetGenericTypeDefinition() == typeof(Godot.Collections.Array<>);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
|
/// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
|
||||||
|
@ -28,10 +26,20 @@ namespace Godot
|
||||||
/// <exception cref="System.InvalidOperationException">
|
/// <exception cref="System.InvalidOperationException">
|
||||||
/// <paramref name="type"/> is not a generic type. That is, IsGenericType returns false.
|
/// <paramref name="type"/> is not a generic type. That is, IsGenericType returns false.
|
||||||
/// </exception>
|
/// </exception>
|
||||||
static bool TypeIsGenericDictionary(Type type)
|
static bool TypeIsGenericDictionary(Type type) =>
|
||||||
{
|
type.GetGenericTypeDefinition() == typeof(Godot.Collections.Dictionary<,>);
|
||||||
return type.GetGenericTypeDefinition() == typeof(Godot.Collections.Dictionary<,>);
|
|
||||||
}
|
static bool TypeIsSystemGenericList(Type type) =>
|
||||||
|
type.GetGenericTypeDefinition() == typeof(System.Collections.Generic.List<>);
|
||||||
|
|
||||||
|
static bool TypeIsSystemGenericDictionary(Type type) =>
|
||||||
|
type.GetGenericTypeDefinition() == typeof(System.Collections.Generic.Dictionary<,>);
|
||||||
|
|
||||||
|
static bool TypeIsGenericIEnumerable(Type type) => type.GetGenericTypeDefinition() == typeof(IEnumerable<>);
|
||||||
|
|
||||||
|
static bool TypeIsGenericICollection(Type type) => type.GetGenericTypeDefinition() == typeof(ICollection<>);
|
||||||
|
|
||||||
|
static bool TypeIsGenericIDictionary(Type type) => type.GetGenericTypeDefinition() == typeof(IDictionary<,>);
|
||||||
|
|
||||||
static void ArrayGetElementType(Type arrayType, out Type elementType)
|
static void ArrayGetElementType(Type arrayType, out Type elementType)
|
||||||
{
|
{
|
||||||
|
@ -45,105 +53,6 @@ namespace Godot
|
||||||
valueType = genericArgs[1];
|
valueType = genericArgs[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool GenericIEnumerableIsAssignableFromType(Type type)
|
|
||||||
{
|
|
||||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
foreach (var interfaceType in type.GetInterfaces())
|
|
||||||
{
|
|
||||||
if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Type baseType = type.BaseType;
|
|
||||||
|
|
||||||
if (baseType == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return GenericIEnumerableIsAssignableFromType(baseType);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool GenericIDictionaryIsAssignableFromType(Type type)
|
|
||||||
{
|
|
||||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IDictionary<,>))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
foreach (var interfaceType in type.GetInterfaces())
|
|
||||||
{
|
|
||||||
if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IDictionary<,>))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Type baseType = type.BaseType;
|
|
||||||
|
|
||||||
if (baseType == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return GenericIDictionaryIsAssignableFromType(baseType);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool GenericIEnumerableIsAssignableFromType(Type type, out Type elementType)
|
|
||||||
{
|
|
||||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
|
|
||||||
{
|
|
||||||
elementType = type.GetGenericArguments()[0];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var interfaceType in type.GetInterfaces())
|
|
||||||
{
|
|
||||||
if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
|
|
||||||
{
|
|
||||||
elementType = interfaceType.GetGenericArguments()[0];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Type baseType = type.BaseType;
|
|
||||||
|
|
||||||
if (baseType == null)
|
|
||||||
{
|
|
||||||
elementType = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return GenericIEnumerableIsAssignableFromType(baseType, out elementType);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool GenericIDictionaryIsAssignableFromType(Type type, out Type keyType, out Type valueType)
|
|
||||||
{
|
|
||||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IDictionary<,>))
|
|
||||||
{
|
|
||||||
var genericArgs = type.GetGenericArguments();
|
|
||||||
keyType = genericArgs[0];
|
|
||||||
valueType = genericArgs[1];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var interfaceType in type.GetInterfaces())
|
|
||||||
{
|
|
||||||
if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IDictionary<,>))
|
|
||||||
{
|
|
||||||
var genericArgs = interfaceType.GetGenericArguments();
|
|
||||||
keyType = genericArgs[0];
|
|
||||||
valueType = genericArgs[1];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Type baseType = type.BaseType;
|
|
||||||
|
|
||||||
if (baseType == null)
|
|
||||||
{
|
|
||||||
keyType = null;
|
|
||||||
valueType = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return GenericIDictionaryIsAssignableFromType(baseType, out keyType, out valueType);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Type MakeGenericArrayType(Type elemType)
|
static Type MakeGenericArrayType(Type elemType)
|
||||||
{
|
{
|
||||||
return typeof(Godot.Collections.Array<>).MakeGenericType(elemType);
|
return typeof(Godot.Collections.Array<>).MakeGenericType(elemType);
|
||||||
|
@ -153,60 +62,5 @@ namespace Godot
|
||||||
{
|
{
|
||||||
return typeof(Godot.Collections.Dictionary<,>).MakeGenericType(keyType, valueType);
|
return typeof(Godot.Collections.Dictionary<,>).MakeGenericType(keyType, valueType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Add support for IEnumerable<T> and IDictionary<TKey, TValue>
|
|
||||||
// TODO: EnumerableToArray and IDictionaryToDictionary can be optimized
|
|
||||||
|
|
||||||
internal static void EnumerableToArray(IEnumerable enumerable, IntPtr godotArrayPtr)
|
|
||||||
{
|
|
||||||
if (enumerable is ICollection collection)
|
|
||||||
{
|
|
||||||
int count = collection.Count;
|
|
||||||
|
|
||||||
object[] tempArray = new object[count];
|
|
||||||
collection.CopyTo(tempArray, 0);
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
Array.godot_icall_Array_Add(godotArrayPtr, tempArray[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (object element in enumerable)
|
|
||||||
{
|
|
||||||
Array.godot_icall_Array_Add(godotArrayPtr, element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void IDictionaryToDictionary(IDictionary dictionary, IntPtr godotDictionaryPtr)
|
|
||||||
{
|
|
||||||
foreach (DictionaryEntry entry in dictionary)
|
|
||||||
{
|
|
||||||
Dictionary.godot_icall_Dictionary_Add(godotDictionaryPtr, entry.Key, entry.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void GenericIDictionaryToDictionary(object dictionary, IntPtr godotDictionaryPtr)
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
if (!GenericIDictionaryIsAssignableFromType(dictionary.GetType()))
|
|
||||||
throw new InvalidOperationException("The type does not implement IDictionary<,>");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// TODO: Can we optimize this?
|
|
||||||
|
|
||||||
var keys = ((IEnumerable)dictionary.GetType().GetProperty("Keys").GetValue(dictionary)).GetEnumerator();
|
|
||||||
var values = ((IEnumerable)dictionary.GetType().GetProperty("Values").GetValue(dictionary)).GetEnumerator();
|
|
||||||
|
|
||||||
while (keys.MoveNext() && values.MoveNext())
|
|
||||||
{
|
|
||||||
object key = keys.Current;
|
|
||||||
object value = values.Current;
|
|
||||||
|
|
||||||
Dictionary.godot_icall_Dictionary_Add(godotDictionaryPtr, key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,7 @@ void CachedData::clear_corlib_cache() {
|
||||||
class_IntPtr = NULL;
|
class_IntPtr = NULL;
|
||||||
|
|
||||||
class_System_Collections_IEnumerable = NULL;
|
class_System_Collections_IEnumerable = NULL;
|
||||||
|
class_System_Collections_ICollection = NULL;
|
||||||
class_System_Collections_IDictionary = NULL;
|
class_System_Collections_IDictionary = NULL;
|
||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
|
@ -162,22 +163,18 @@ void CachedData::clear_godot_api_cache() {
|
||||||
|
|
||||||
methodthunk_MarshalUtils_TypeIsGenericArray.nullify();
|
methodthunk_MarshalUtils_TypeIsGenericArray.nullify();
|
||||||
methodthunk_MarshalUtils_TypeIsGenericDictionary.nullify();
|
methodthunk_MarshalUtils_TypeIsGenericDictionary.nullify();
|
||||||
|
methodthunk_MarshalUtils_TypeIsSystemGenericList.nullify();
|
||||||
|
methodthunk_MarshalUtils_TypeIsSystemGenericDictionary.nullify();
|
||||||
|
methodthunk_MarshalUtils_TypeIsGenericIEnumerable.nullify();
|
||||||
|
methodthunk_MarshalUtils_TypeIsGenericICollection.nullify();
|
||||||
|
methodthunk_MarshalUtils_TypeIsGenericIDictionary.nullify();
|
||||||
|
|
||||||
methodthunk_MarshalUtils_ArrayGetElementType.nullify();
|
methodthunk_MarshalUtils_ArrayGetElementType.nullify();
|
||||||
methodthunk_MarshalUtils_DictionaryGetKeyValueTypes.nullify();
|
methodthunk_MarshalUtils_DictionaryGetKeyValueTypes.nullify();
|
||||||
|
|
||||||
methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType.nullify();
|
|
||||||
methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType.nullify();
|
|
||||||
methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType_with_info.nullify();
|
|
||||||
methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType_with_info.nullify();
|
|
||||||
|
|
||||||
methodthunk_MarshalUtils_MakeGenericArrayType.nullify();
|
methodthunk_MarshalUtils_MakeGenericArrayType.nullify();
|
||||||
methodthunk_MarshalUtils_MakeGenericDictionaryType.nullify();
|
methodthunk_MarshalUtils_MakeGenericDictionaryType.nullify();
|
||||||
|
|
||||||
methodthunk_MarshalUtils_EnumerableToArray.nullify();
|
|
||||||
methodthunk_MarshalUtils_IDictionaryToDictionary.nullify();
|
|
||||||
methodthunk_MarshalUtils_GenericIDictionaryToDictionary.nullify();
|
|
||||||
|
|
||||||
// End of MarshalUtils methods
|
// End of MarshalUtils methods
|
||||||
|
|
||||||
task_scheduler_handle = Ref<MonoGCHandle>();
|
task_scheduler_handle = Ref<MonoGCHandle>();
|
||||||
|
@ -204,6 +201,7 @@ void update_corlib_cache() {
|
||||||
CACHE_CLASS_AND_CHECK(IntPtr, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_intptr_class()));
|
CACHE_CLASS_AND_CHECK(IntPtr, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_intptr_class()));
|
||||||
|
|
||||||
CACHE_CLASS_AND_CHECK(System_Collections_IEnumerable, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IEnumerable"));
|
CACHE_CLASS_AND_CHECK(System_Collections_IEnumerable, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IEnumerable"));
|
||||||
|
CACHE_CLASS_AND_CHECK(System_Collections_ICollection, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "ICollection"));
|
||||||
CACHE_CLASS_AND_CHECK(System_Collections_IDictionary, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IDictionary"));
|
CACHE_CLASS_AND_CHECK(System_Collections_IDictionary, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IDictionary"));
|
||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
|
@ -279,22 +277,18 @@ void update_godot_api_cache() {
|
||||||
|
|
||||||
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericArray, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericArray", 1));
|
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericArray, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericArray", 1));
|
||||||
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericDictionary", 1));
|
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericDictionary", 1));
|
||||||
|
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsSystemGenericList, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsSystemGenericList", 1));
|
||||||
|
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsSystemGenericDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsSystemGenericDictionary", 1));
|
||||||
|
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericIEnumerable, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericIEnumerable", 1));
|
||||||
|
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericICollection, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericICollection", 1));
|
||||||
|
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericIDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericIDictionary", 1));
|
||||||
|
|
||||||
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArrayGetElementType, GODOT_API_CLASS(MarshalUtils)->get_method("ArrayGetElementType", 2));
|
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArrayGetElementType, GODOT_API_CLASS(MarshalUtils)->get_method("ArrayGetElementType", 2));
|
||||||
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, GODOT_API_CLASS(MarshalUtils)->get_method("DictionaryGetKeyValueTypes", 3));
|
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, GODOT_API_CLASS(MarshalUtils)->get_method("DictionaryGetKeyValueTypes", 3));
|
||||||
|
|
||||||
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType, GODOT_API_CLASS(MarshalUtils)->get_method("GenericIEnumerableIsAssignableFromType", 1));
|
|
||||||
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryIsAssignableFromType, GODOT_API_CLASS(MarshalUtils)->get_method("GenericIDictionaryIsAssignableFromType", 1));
|
|
||||||
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info, GODOT_API_CLASS(MarshalUtils)->get_method("GenericIEnumerableIsAssignableFromType", 2));
|
|
||||||
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryIsAssignableFromType_with_info, GODOT_API_CLASS(MarshalUtils)->get_method("GenericIDictionaryIsAssignableFromType", 3));
|
|
||||||
|
|
||||||
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericArrayType, GODOT_API_CLASS(MarshalUtils)->get_method("MakeGenericArrayType", 1));
|
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericArrayType, GODOT_API_CLASS(MarshalUtils)->get_method("MakeGenericArrayType", 1));
|
||||||
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericDictionaryType, GODOT_API_CLASS(MarshalUtils)->get_method("MakeGenericDictionaryType", 2));
|
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericDictionaryType, GODOT_API_CLASS(MarshalUtils)->get_method("MakeGenericDictionaryType", 2));
|
||||||
|
|
||||||
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, EnumerableToArray, GODOT_API_CLASS(MarshalUtils)->get_method("EnumerableToArray", 2));
|
|
||||||
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IDictionaryToDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("IDictionaryToDictionary", 2));
|
|
||||||
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryToDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("GenericIDictionaryToDictionary", 2));
|
|
||||||
|
|
||||||
// End of MarshalUtils methods
|
// End of MarshalUtils methods
|
||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
|
|
|
@ -58,6 +58,7 @@ struct CachedData {
|
||||||
GDMonoClass *class_IntPtr; // System.IntPtr
|
GDMonoClass *class_IntPtr; // System.IntPtr
|
||||||
|
|
||||||
GDMonoClass *class_System_Collections_IEnumerable;
|
GDMonoClass *class_System_Collections_IEnumerable;
|
||||||
|
GDMonoClass *class_System_Collections_ICollection;
|
||||||
GDMonoClass *class_System_Collections_IDictionary;
|
GDMonoClass *class_System_Collections_IDictionary;
|
||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
|
@ -132,22 +133,18 @@ struct CachedData {
|
||||||
|
|
||||||
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericArray;
|
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericArray;
|
||||||
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericDictionary;
|
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericDictionary;
|
||||||
|
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsSystemGenericList;
|
||||||
|
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsSystemGenericDictionary;
|
||||||
|
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIEnumerable;
|
||||||
|
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericICollection;
|
||||||
|
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIDictionary;
|
||||||
|
|
||||||
GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_ArrayGetElementType;
|
GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_ArrayGetElementType;
|
||||||
GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **, MonoReflectionType **> methodthunk_MarshalUtils_DictionaryGetKeyValueTypes;
|
GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **, MonoReflectionType **> methodthunk_MarshalUtils_DictionaryGetKeyValueTypes;
|
||||||
|
|
||||||
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType;
|
|
||||||
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType;
|
|
||||||
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType_with_info;
|
|
||||||
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *, MonoReflectionType **, MonoReflectionType **> methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType_with_info;
|
|
||||||
|
|
||||||
GDMonoMethodThunkR<MonoReflectionType *, MonoReflectionType *> methodthunk_MarshalUtils_MakeGenericArrayType;
|
GDMonoMethodThunkR<MonoReflectionType *, MonoReflectionType *> methodthunk_MarshalUtils_MakeGenericArrayType;
|
||||||
GDMonoMethodThunkR<MonoReflectionType *, MonoReflectionType *, MonoReflectionType *> methodthunk_MarshalUtils_MakeGenericDictionaryType;
|
GDMonoMethodThunkR<MonoReflectionType *, MonoReflectionType *, MonoReflectionType *> methodthunk_MarshalUtils_MakeGenericDictionaryType;
|
||||||
|
|
||||||
GDMonoMethodThunk<MonoObject *, Array *> methodthunk_MarshalUtils_EnumerableToArray;
|
|
||||||
GDMonoMethodThunk<MonoObject *, Dictionary *> methodthunk_MarshalUtils_IDictionaryToDictionary;
|
|
||||||
GDMonoMethodThunk<MonoObject *, Dictionary *> methodthunk_MarshalUtils_GenericIDictionaryToDictionary;
|
|
||||||
|
|
||||||
// End of MarshalUtils methods
|
// End of MarshalUtils methods
|
||||||
|
|
||||||
Ref<MonoGCHandle> task_scheduler_handle;
|
Ref<MonoGCHandle> task_scheduler_handle;
|
||||||
|
@ -177,14 +174,6 @@ inline void clear_godot_api_cache() {
|
||||||
cached_data.clear_godot_api_cache();
|
cached_data.clear_godot_api_cache();
|
||||||
}
|
}
|
||||||
|
|
||||||
_FORCE_INLINE_ bool tools_godot_api_check() {
|
|
||||||
#ifdef TOOLS_ENABLED
|
|
||||||
return cached_data.godot_api_cache_updated;
|
|
||||||
#else
|
|
||||||
return true; // Assume it's updated if this was called, otherwise it's a bug
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace GDMonoCache
|
} // namespace GDMonoCache
|
||||||
|
|
||||||
#define CACHED_CLASS(m_class) (GDMonoCache::cached_data.class_##m_class)
|
#define CACHED_CLASS(m_class) (GDMonoCache::cached_data.class_##m_class)
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "gd_mono_class.h"
|
#include "gd_mono_class.h"
|
||||||
|
|
||||||
#include <mono/metadata/attrdefs.h>
|
#include <mono/metadata/attrdefs.h>
|
||||||
|
#include <mono/metadata/debug-helpers.h>
|
||||||
|
|
||||||
#include "gd_mono_assembly.h"
|
#include "gd_mono_assembly.h"
|
||||||
#include "gd_mono_cache.h"
|
#include "gd_mono_cache.h"
|
||||||
|
@ -55,7 +56,11 @@ String GDMonoClass::get_full_name() const {
|
||||||
return get_full_name(mono_class);
|
return get_full_name(mono_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
MonoType *GDMonoClass::get_mono_type() {
|
String GDMonoClass::get_type_desc() const {
|
||||||
|
return GDMonoUtils::get_type_desc(get_mono_type());
|
||||||
|
}
|
||||||
|
|
||||||
|
MonoType *GDMonoClass::get_mono_type() const {
|
||||||
// Careful, you cannot compare two MonoType*.
|
// Careful, you cannot compare two MonoType*.
|
||||||
// There is mono_metadata_type_equal, how is this different from comparing two MonoClass*?
|
// There is mono_metadata_type_equal, how is this different from comparing two MonoClass*?
|
||||||
return get_mono_type(mono_class);
|
return get_mono_type(mono_class);
|
||||||
|
@ -264,6 +269,12 @@ bool GDMonoClass::implements_interface(GDMonoClass *p_interface) {
|
||||||
return mono_class_implements_interface(mono_class, p_interface->get_mono_ptr());
|
return mono_class_implements_interface(mono_class, p_interface->get_mono_ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GDMonoClass::has_public_parameterless_ctor() {
|
||||||
|
|
||||||
|
GDMonoMethod *ctor = get_method(".ctor", 0);
|
||||||
|
return ctor && ctor->get_visibility() == IMonoClassMember::PUBLIC;
|
||||||
|
}
|
||||||
|
|
||||||
GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, int p_params_count) {
|
GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, int p_params_count) {
|
||||||
|
|
||||||
MethodKey key = MethodKey(p_name, p_params_count);
|
MethodKey key = MethodKey(p_name, p_params_count);
|
||||||
|
@ -328,6 +339,9 @@ GDMonoMethod *GDMonoClass::get_method_with_desc(const String &p_description, boo
|
||||||
MonoMethod *method = mono_method_desc_search_in_class(desc, mono_class);
|
MonoMethod *method = mono_method_desc_search_in_class(desc, mono_class);
|
||||||
mono_method_desc_free(desc);
|
mono_method_desc_free(desc);
|
||||||
|
|
||||||
|
if (!method)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
ERR_FAIL_COND_V(mono_method_get_class(method) != mono_class, NULL);
|
ERR_FAIL_COND_V(mono_method_get_class(method) != mono_class, NULL);
|
||||||
|
|
||||||
return get_method(method);
|
return get_method(method);
|
||||||
|
|
|
@ -31,8 +31,6 @@
|
||||||
#ifndef GD_MONO_CLASS_H
|
#ifndef GD_MONO_CLASS_H
|
||||||
#define GD_MONO_CLASS_H
|
#define GD_MONO_CLASS_H
|
||||||
|
|
||||||
#include <mono/metadata/debug-helpers.h>
|
|
||||||
|
|
||||||
#include "core/map.h"
|
#include "core/map.h"
|
||||||
#include "core/ustring.h"
|
#include "core/ustring.h"
|
||||||
|
|
||||||
|
@ -107,7 +105,8 @@ public:
|
||||||
static MonoType *get_mono_type(MonoClass *p_mono_class);
|
static MonoType *get_mono_type(MonoClass *p_mono_class);
|
||||||
|
|
||||||
String get_full_name() const;
|
String get_full_name() const;
|
||||||
MonoType *get_mono_type();
|
String get_type_desc() const;
|
||||||
|
MonoType *get_mono_type() const;
|
||||||
|
|
||||||
uint32_t get_flags() const;
|
uint32_t get_flags() const;
|
||||||
bool is_static() const;
|
bool is_static() const;
|
||||||
|
@ -137,6 +136,7 @@ public:
|
||||||
void fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base);
|
void fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base);
|
||||||
|
|
||||||
bool implements_interface(GDMonoClass *p_interface);
|
bool implements_interface(GDMonoClass *p_interface);
|
||||||
|
bool has_public_parameterless_ctor();
|
||||||
|
|
||||||
GDMonoMethod *get_method(const StringName &p_name, int p_params_count = 0);
|
GDMonoMethod *get_method(const StringName &p_name, int p_params_count = 0);
|
||||||
GDMonoMethod *get_method(MonoMethod *p_raw_method);
|
GDMonoMethod *get_method(MonoMethod *p_raw_method);
|
||||||
|
|
|
@ -313,56 +313,22 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CACHED_CLASS(Dictionary) == type_class) {
|
// Godot.Collections.Dictionary or IDictionary
|
||||||
|
if (CACHED_CLASS(Dictionary) == type_class || type_class == CACHED_CLASS(System_Collections_IDictionary)) {
|
||||||
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary));
|
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary));
|
||||||
mono_field_set_value(p_object, mono_field, managed);
|
mono_field_set_value(p_object, mono_field, managed);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CACHED_CLASS(Array) == type_class) {
|
// Godot.Collections.Array or ICollection or IEnumerable
|
||||||
|
if (CACHED_CLASS(Array) == type_class ||
|
||||||
|
type_class == CACHED_CLASS(System_Collections_ICollection) ||
|
||||||
|
type_class == CACHED_CLASS(System_Collections_IEnumerable)) {
|
||||||
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
|
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
|
||||||
mono_field_set_value(p_object, mono_field, managed);
|
mono_field_set_value(p_object, mono_field, managed);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The order in which we check the following interfaces is very important (dictionaries and generics first)
|
|
||||||
|
|
||||||
MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), type_class->get_mono_type());
|
|
||||||
|
|
||||||
MonoReflectionType *key_reftype, *value_reftype;
|
|
||||||
if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) {
|
|
||||||
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(),
|
|
||||||
GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype));
|
|
||||||
mono_field_set_value(p_object, mono_field, managed);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
|
|
||||||
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary));
|
|
||||||
mono_field_set_value(p_object, mono_field, managed);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
MonoReflectionType *elem_reftype;
|
|
||||||
if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) {
|
|
||||||
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(),
|
|
||||||
GDMonoUtils::Marshal::make_generic_array_type(elem_reftype));
|
|
||||||
mono_field_set_value(p_object, mono_field, managed);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
|
|
||||||
if (GDMonoCache::tools_godot_api_check()) {
|
|
||||||
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
|
|
||||||
mono_field_set_value(p_object, mono_field, managed);
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
MonoObject *managed = (MonoObject *)GDMonoMarshal::Array_to_mono_array(p_value.operator Array());
|
|
||||||
mono_field_set_value(p_object, mono_field, managed);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ERR_FAIL_MSG("Attempted to set the value of a field of unmarshallable type: '" + type_class->get_name() + "'.");
|
ERR_FAIL_MSG("Attempted to set the value of a field of unmarshallable type: '" + type_class->get_name() + "'.");
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -469,52 +435,62 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
|
||||||
case MONO_TYPE_GENERICINST: {
|
case MONO_TYPE_GENERICINST: {
|
||||||
MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), type.type_class->get_mono_type());
|
MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), type.type_class->get_mono_type());
|
||||||
|
|
||||||
|
// Godot.Collections.Dictionary<TKey, TValue>
|
||||||
if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
|
if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
|
||||||
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), type.type_class);
|
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), type.type_class);
|
||||||
mono_field_set_value(p_object, mono_field, managed);
|
mono_field_set_value(p_object, mono_field, managed);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Godot.Collections.Array<T>
|
||||||
if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
|
if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
|
||||||
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), type.type_class);
|
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), type.type_class);
|
||||||
mono_field_set_value(p_object, mono_field, managed);
|
mono_field_set_value(p_object, mono_field, managed);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The order in which we check the following interfaces is very important (dictionaries and generics first)
|
// System.Collections.Generic.Dictionary<TKey, TValue>
|
||||||
|
if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) {
|
||||||
MonoReflectionType *key_reftype, *value_reftype;
|
MonoReflectionType *key_reftype = nullptr;
|
||||||
if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) {
|
MonoReflectionType *value_reftype = nullptr;
|
||||||
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(),
|
GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype);
|
||||||
GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype));
|
MonoObject *managed = GDMonoMarshal::Dictionary_to_system_generic_dict(p_value.operator Dictionary(),
|
||||||
|
type.type_class, key_reftype, value_reftype);
|
||||||
mono_field_set_value(p_object, mono_field, managed);
|
mono_field_set_value(p_object, mono_field, managed);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
|
// System.Collections.Generic.List<T>
|
||||||
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary));
|
if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) {
|
||||||
|
MonoReflectionType *elem_reftype = nullptr;
|
||||||
|
GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
|
||||||
|
MonoObject *managed = GDMonoMarshal::Array_to_system_generic_list(p_value.operator Array(),
|
||||||
|
type.type_class, elem_reftype);
|
||||||
mono_field_set_value(p_object, mono_field, managed);
|
mono_field_set_value(p_object, mono_field, managed);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
MonoReflectionType *elem_reftype;
|
// IDictionary<TKey, TValue>
|
||||||
if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) {
|
if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) {
|
||||||
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(),
|
MonoReflectionType *key_reftype;
|
||||||
GDMonoUtils::Marshal::make_generic_array_type(elem_reftype));
|
MonoReflectionType *value_reftype;
|
||||||
|
GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype);
|
||||||
|
GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype);
|
||||||
|
|
||||||
|
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), godot_dict_class);
|
||||||
mono_field_set_value(p_object, mono_field, managed);
|
mono_field_set_value(p_object, mono_field, managed);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
|
// ICollection<T> or IEnumerable<T>
|
||||||
if (GDMonoCache::tools_godot_api_check()) {
|
if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) {
|
||||||
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
|
MonoReflectionType *elem_reftype;
|
||||||
mono_field_set_value(p_object, mono_field, managed);
|
GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
|
||||||
break;
|
GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(elem_reftype);
|
||||||
} else {
|
|
||||||
MonoObject *managed = (MonoObject *)GDMonoMarshal::Array_to_mono_array(p_value.operator Array());
|
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), godot_array_class);
|
||||||
mono_field_set_value(p_object, mono_field, managed);
|
mono_field_set_value(p_object, mono_field, managed);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
|
|
@ -162,23 +162,14 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
|
||||||
return Variant::ARRAY;
|
return Variant::ARRAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The order in which we check the following interfaces is very important (dictionaries and generics first)
|
// IDictionary
|
||||||
|
if (p_type.type_class == CACHED_CLASS(System_Collections_IDictionary)) {
|
||||||
MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), type_class->get_mono_type());
|
|
||||||
|
|
||||||
if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype)) {
|
|
||||||
return Variant::DICTIONARY;
|
return Variant::DICTIONARY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
|
// ICollection or IEnumerable
|
||||||
return Variant::DICTIONARY;
|
if (p_type.type_class == CACHED_CLASS(System_Collections_ICollection) ||
|
||||||
}
|
p_type.type_class == CACHED_CLASS(System_Collections_IEnumerable)) {
|
||||||
|
|
||||||
if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype)) {
|
|
||||||
return Variant::ARRAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
|
|
||||||
return Variant::ARRAY;
|
return Variant::ARRAY;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
@ -186,27 +177,33 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
|
||||||
case MONO_TYPE_GENERICINST: {
|
case MONO_TYPE_GENERICINST: {
|
||||||
MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
|
MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
|
||||||
|
|
||||||
|
// Godot.Collections.Dictionary<TKey, TValue>
|
||||||
if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
|
if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
|
||||||
return Variant::DICTIONARY;
|
return Variant::DICTIONARY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Godot.Collections.Array<T>
|
||||||
if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
|
if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
|
||||||
return Variant::ARRAY;
|
return Variant::ARRAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The order in which we check the following interfaces is very important (dictionaries and generics first)
|
// System.Collections.Generic.Dictionary<TKey, TValue>
|
||||||
|
if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) {
|
||||||
if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype))
|
|
||||||
return Variant::DICTIONARY;
|
|
||||||
|
|
||||||
if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
|
|
||||||
return Variant::DICTIONARY;
|
return Variant::DICTIONARY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype))
|
// System.Collections.Generic.List<T>
|
||||||
|
if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) {
|
||||||
return Variant::ARRAY;
|
return Variant::ARRAY;
|
||||||
|
}
|
||||||
|
|
||||||
if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
|
// IDictionary<TKey, TValue>
|
||||||
|
if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) {
|
||||||
|
return Variant::DICTIONARY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICollection<T> or IEnumerable<T>
|
||||||
|
if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) {
|
||||||
return Variant::ARRAY;
|
return Variant::ARRAY;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
@ -231,7 +228,10 @@ bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_
|
||||||
case MONO_TYPE_GENERICINST: {
|
case MONO_TYPE_GENERICINST: {
|
||||||
MonoReflectionType *array_reftype = mono_type_get_object(mono_domain_get(), p_array_type.type_class->get_mono_type());
|
MonoReflectionType *array_reftype = mono_type_get_object(mono_domain_get(), p_array_type.type_class->get_mono_type());
|
||||||
|
|
||||||
if (GDMonoUtils::Marshal::type_is_generic_array(array_reftype)) {
|
if (GDMonoUtils::Marshal::type_is_generic_array(array_reftype) ||
|
||||||
|
GDMonoUtils::Marshal::type_is_system_generic_list(array_reftype) ||
|
||||||
|
GDMonoUtils::Marshal::type_is_generic_icollection(array_reftype) ||
|
||||||
|
GDMonoUtils::Marshal::type_is_generic_ienumerable(array_reftype)) {
|
||||||
MonoReflectionType *elem_reftype;
|
MonoReflectionType *elem_reftype;
|
||||||
|
|
||||||
GDMonoUtils::Marshal::array_get_element_type(array_reftype, &elem_reftype);
|
GDMonoUtils::Marshal::array_get_element_type(array_reftype, &elem_reftype);
|
||||||
|
@ -239,12 +239,6 @@ bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_
|
||||||
r_elem_type = ManagedType::from_reftype(elem_reftype);
|
r_elem_type = ManagedType::from_reftype(elem_reftype);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MonoReflectionType *elem_reftype;
|
|
||||||
if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(array_reftype, &elem_reftype)) {
|
|
||||||
r_elem_type = ManagedType::from_reftype(elem_reftype);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} break;
|
} break;
|
||||||
default: {
|
default: {
|
||||||
} break;
|
} break;
|
||||||
|
@ -258,7 +252,9 @@ bool try_get_dictionary_key_value_types(const ManagedType &p_dictionary_type, Ma
|
||||||
case MONO_TYPE_GENERICINST: {
|
case MONO_TYPE_GENERICINST: {
|
||||||
MonoReflectionType *dict_reftype = mono_type_get_object(mono_domain_get(), p_dictionary_type.type_class->get_mono_type());
|
MonoReflectionType *dict_reftype = mono_type_get_object(mono_domain_get(), p_dictionary_type.type_class->get_mono_type());
|
||||||
|
|
||||||
if (GDMonoUtils::Marshal::type_is_generic_dictionary(dict_reftype)) {
|
if (GDMonoUtils::Marshal::type_is_generic_dictionary(dict_reftype) ||
|
||||||
|
GDMonoUtils::Marshal::type_is_system_generic_dictionary(dict_reftype) ||
|
||||||
|
GDMonoUtils::Marshal::type_is_generic_idictionary(dict_reftype)) {
|
||||||
MonoReflectionType *key_reftype;
|
MonoReflectionType *key_reftype;
|
||||||
MonoReflectionType *value_reftype;
|
MonoReflectionType *value_reftype;
|
||||||
|
|
||||||
|
@ -268,13 +264,6 @@ bool try_get_dictionary_key_value_types(const ManagedType &p_dictionary_type, Ma
|
||||||
r_value_type = ManagedType::from_reftype(value_reftype);
|
r_value_type = ManagedType::from_reftype(value_reftype);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MonoReflectionType *key_reftype, *value_reftype;
|
|
||||||
if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(dict_reftype, &key_reftype, &value_reftype)) {
|
|
||||||
r_key_type = ManagedType::from_reftype(key_reftype);
|
|
||||||
r_value_type = ManagedType::from_reftype(value_reftype);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} break;
|
} break;
|
||||||
default: {
|
default: {
|
||||||
} break;
|
} break;
|
||||||
|
@ -545,41 +534,17 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
|
||||||
return GDMonoUtils::create_managed_from(p_var->operator RID());
|
return GDMonoUtils::create_managed_from(p_var->operator RID());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CACHED_CLASS(Dictionary) == type_class) {
|
// Godot.Collections.Dictionary or IDictionary
|
||||||
|
if (CACHED_CLASS(Dictionary) == type_class || CACHED_CLASS(System_Collections_IDictionary) == type_class) {
|
||||||
return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
|
return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CACHED_CLASS(Array) == type_class) {
|
// Godot.Collections.Array or ICollection or IEnumerable
|
||||||
|
if (CACHED_CLASS(Array) == type_class ||
|
||||||
|
CACHED_CLASS(System_Collections_ICollection) == type_class ||
|
||||||
|
CACHED_CLASS(System_Collections_IEnumerable) == type_class) {
|
||||||
return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
|
return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
|
||||||
}
|
}
|
||||||
|
|
||||||
// The order in which we check the following interfaces is very important (dictionaries and generics first)
|
|
||||||
|
|
||||||
MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), type_class->get_mono_type());
|
|
||||||
|
|
||||||
MonoReflectionType *key_reftype, *value_reftype;
|
|
||||||
if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) {
|
|
||||||
return GDMonoUtils::create_managed_from(p_var->operator Dictionary(),
|
|
||||||
GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
|
|
||||||
return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
|
|
||||||
}
|
|
||||||
|
|
||||||
MonoReflectionType *elem_reftype;
|
|
||||||
if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) {
|
|
||||||
return GDMonoUtils::create_managed_from(p_var->operator Array(),
|
|
||||||
GDMonoUtils::Marshal::make_generic_array_type(elem_reftype));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
|
|
||||||
if (GDMonoCache::tools_godot_api_check()) {
|
|
||||||
return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
|
|
||||||
} else {
|
|
||||||
return (MonoObject *)GDMonoMarshal::Array_to_mono_array(p_var->operator Array());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} break;
|
} break;
|
||||||
case MONO_TYPE_OBJECT: {
|
case MONO_TYPE_OBJECT: {
|
||||||
// Variant
|
// Variant
|
||||||
|
@ -674,38 +639,48 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
|
||||||
case MONO_TYPE_GENERICINST: {
|
case MONO_TYPE_GENERICINST: {
|
||||||
MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
|
MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
|
||||||
|
|
||||||
|
// Godot.Collections.Dictionary<TKey, TValue>
|
||||||
if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
|
if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
|
||||||
return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), p_type.type_class);
|
return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), p_type.type_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Godot.Collections.Array<T>
|
||||||
if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
|
if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
|
||||||
return GDMonoUtils::create_managed_from(p_var->operator Array(), p_type.type_class);
|
return GDMonoUtils::create_managed_from(p_var->operator Array(), p_type.type_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The order in which we check the following interfaces is very important (dictionaries and generics first)
|
// System.Collections.Generic.Dictionary<TKey, TValue>
|
||||||
|
if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) {
|
||||||
MonoReflectionType *key_reftype, *value_reftype;
|
MonoReflectionType *key_reftype = nullptr;
|
||||||
if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype, &key_reftype, &value_reftype)) {
|
MonoReflectionType *value_reftype = nullptr;
|
||||||
return GDMonoUtils::create_managed_from(p_var->operator Dictionary(),
|
GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype);
|
||||||
GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype));
|
return Dictionary_to_system_generic_dict(p_var->operator Dictionary(), p_type.type_class, key_reftype, value_reftype);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
|
// System.Collections.Generic.List<T>
|
||||||
return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
|
if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) {
|
||||||
|
MonoReflectionType *elem_reftype = nullptr;
|
||||||
|
GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
|
||||||
|
return Array_to_system_generic_list(p_var->operator Array(), p_type.type_class, elem_reftype);
|
||||||
}
|
}
|
||||||
|
|
||||||
MonoReflectionType *elem_reftype;
|
// IDictionary<TKey, TValue>
|
||||||
if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype, &elem_reftype)) {
|
if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) {
|
||||||
return GDMonoUtils::create_managed_from(p_var->operator Array(),
|
MonoReflectionType *key_reftype;
|
||||||
GDMonoUtils::Marshal::make_generic_array_type(elem_reftype));
|
MonoReflectionType *value_reftype;
|
||||||
|
GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype);
|
||||||
|
GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype);
|
||||||
|
|
||||||
|
return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), godot_dict_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
|
// ICollection<T> or IEnumerable<T>
|
||||||
if (GDMonoCache::tools_godot_api_check()) {
|
if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) {
|
||||||
return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
|
MonoReflectionType *elem_reftype;
|
||||||
} else {
|
GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
|
||||||
return (MonoObject *)GDMonoMarshal::Array_to_mono_array(p_var->operator Array());
|
GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(elem_reftype);
|
||||||
}
|
|
||||||
|
return GDMonoUtils::create_managed_from(p_var->operator Array(), godot_array_class);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
} break;
|
} break;
|
||||||
|
@ -854,13 +829,7 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
|
||||||
return ptr ? Variant(*ptr) : Variant();
|
return ptr ? Variant(*ptr) : Variant();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CACHED_CLASS(Array) == type_class) {
|
// Godot.Collections.Dictionary
|
||||||
MonoException *exc = NULL;
|
|
||||||
Array *ptr = CACHED_METHOD_THUNK(Array, GetPtr).invoke(p_obj, &exc);
|
|
||||||
UNHANDLED_EXCEPTION(exc);
|
|
||||||
return ptr ? Variant(*ptr) : Variant();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CACHED_CLASS(Dictionary) == type_class) {
|
if (CACHED_CLASS(Dictionary) == type_class) {
|
||||||
MonoException *exc = NULL;
|
MonoException *exc = NULL;
|
||||||
Dictionary *ptr = CACHED_METHOD_THUNK(Dictionary, GetPtr).invoke(p_obj, &exc);
|
Dictionary *ptr = CACHED_METHOD_THUNK(Dictionary, GetPtr).invoke(p_obj, &exc);
|
||||||
|
@ -868,30 +837,19 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
|
||||||
return ptr ? Variant(*ptr) : Variant();
|
return ptr ? Variant(*ptr) : Variant();
|
||||||
}
|
}
|
||||||
|
|
||||||
// The order in which we check the following interfaces is very important (dictionaries and generics first)
|
// Godot.Collections.Array
|
||||||
|
if (CACHED_CLASS(Array) == type_class) {
|
||||||
MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), type_class->get_mono_type());
|
MonoException *exc = NULL;
|
||||||
|
Array *ptr = CACHED_METHOD_THUNK(Array, GetPtr).invoke(p_obj, &exc);
|
||||||
if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype)) {
|
UNHANDLED_EXCEPTION(exc);
|
||||||
return GDMonoUtils::Marshal::generic_idictionary_to_dictionary(p_obj);
|
return ptr ? Variant(*ptr) : Variant();
|
||||||
}
|
|
||||||
|
|
||||||
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
|
|
||||||
return GDMonoUtils::Marshal::idictionary_to_dictionary(p_obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype)) {
|
|
||||||
return GDMonoUtils::Marshal::enumerable_to_array(p_obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
|
|
||||||
return GDMonoUtils::Marshal::enumerable_to_array(p_obj);
|
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case MONO_TYPE_GENERICINST: {
|
case MONO_TYPE_GENERICINST: {
|
||||||
MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
|
MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
|
||||||
|
|
||||||
|
// Godot.Collections.Dictionary<TKey, TValue>
|
||||||
if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
|
if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
|
||||||
MonoException *exc = NULL;
|
MonoException *exc = NULL;
|
||||||
MonoObject *ret = p_type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
|
MonoObject *ret = p_type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
|
||||||
|
@ -899,6 +857,7 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
|
||||||
return *unbox<Dictionary *>(ret);
|
return *unbox<Dictionary *>(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Godot.Collections.Array<T>
|
||||||
if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
|
if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
|
||||||
MonoException *exc = NULL;
|
MonoException *exc = NULL;
|
||||||
MonoObject *ret = p_type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
|
MonoObject *ret = p_type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
|
||||||
|
@ -906,22 +865,19 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
|
||||||
return *unbox<Array *>(ret);
|
return *unbox<Array *>(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The order in which we check the following interfaces is very important (dictionaries and generics first)
|
// System.Collections.Generic.Dictionary<TKey, TValue>
|
||||||
|
if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) {
|
||||||
if (GDMonoUtils::Marshal::generic_idictionary_is_assignable_from(reftype)) {
|
MonoReflectionType *key_reftype = nullptr;
|
||||||
return GDMonoUtils::Marshal::generic_idictionary_to_dictionary(p_obj);
|
MonoReflectionType *value_reftype = nullptr;
|
||||||
|
GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype);
|
||||||
|
return system_generic_dict_to_Dictionary(p_obj, p_type.type_class, key_reftype, value_reftype);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
|
// System.Collections.Generic.List<T>
|
||||||
return GDMonoUtils::Marshal::idictionary_to_dictionary(p_obj);
|
if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) {
|
||||||
}
|
MonoReflectionType *elem_reftype = nullptr;
|
||||||
|
GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
|
||||||
if (GDMonoUtils::Marshal::generic_ienumerable_is_assignable_from(reftype)) {
|
return system_generic_list_to_Array(p_obj, p_type.type_class, elem_reftype);
|
||||||
return GDMonoUtils::Marshal::enumerable_to_array(p_obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
|
|
||||||
return GDMonoUtils::Marshal::enumerable_to_array(p_obj);
|
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
@ -978,6 +934,80 @@ String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MonoObject *Dictionary_to_system_generic_dict(const Dictionary &p_dict, GDMonoClass *p_class, MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype) {
|
||||||
|
String ctor_desc = ":.ctor(System.Collections.Generic.IDictionary`2<" + GDMonoUtils::get_type_desc(p_key_reftype) +
|
||||||
|
", " + GDMonoUtils::get_type_desc(p_value_reftype) + ">)";
|
||||||
|
GDMonoMethod *ctor = p_class->get_method_with_desc(ctor_desc, true);
|
||||||
|
CRASH_COND(ctor == nullptr);
|
||||||
|
|
||||||
|
MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr());
|
||||||
|
ERR_FAIL_NULL_V(mono_object, nullptr);
|
||||||
|
|
||||||
|
GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(p_key_reftype, p_value_reftype);
|
||||||
|
MonoObject *godot_dict = GDMonoUtils::create_managed_from(p_dict, godot_dict_class);
|
||||||
|
|
||||||
|
void *ctor_args[1] = { godot_dict };
|
||||||
|
|
||||||
|
MonoException *exc = nullptr;
|
||||||
|
ctor->invoke_raw(mono_object, ctor_args, &exc);
|
||||||
|
UNHANDLED_EXCEPTION(exc);
|
||||||
|
|
||||||
|
return mono_object;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary system_generic_dict_to_Dictionary(MonoObject *p_obj, [[maybe_unused]] GDMonoClass *p_class, MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype) {
|
||||||
|
GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(p_key_reftype, p_value_reftype);
|
||||||
|
String ctor_desc = ":.ctor(System.Collections.Generic.IDictionary`2<" + GDMonoUtils::get_type_desc(p_key_reftype) +
|
||||||
|
", " + GDMonoUtils::get_type_desc(p_value_reftype) + ">)";
|
||||||
|
GDMonoMethod *godot_dict_ctor = godot_dict_class->get_method_with_desc(ctor_desc, true);
|
||||||
|
CRASH_COND(godot_dict_ctor == nullptr);
|
||||||
|
|
||||||
|
MonoObject *godot_dict = mono_object_new(mono_domain_get(), godot_dict_class->get_mono_ptr());
|
||||||
|
ERR_FAIL_NULL_V(godot_dict, Dictionary());
|
||||||
|
|
||||||
|
void *ctor_args[1] = { p_obj };
|
||||||
|
|
||||||
|
MonoException *exc = nullptr;
|
||||||
|
godot_dict_ctor->invoke_raw(godot_dict, ctor_args, &exc);
|
||||||
|
UNHANDLED_EXCEPTION(exc);
|
||||||
|
|
||||||
|
exc = nullptr;
|
||||||
|
MonoObject *ret = godot_dict_class->get_method("GetPtr")->invoke(godot_dict, &exc);
|
||||||
|
UNHANDLED_EXCEPTION(exc);
|
||||||
|
|
||||||
|
return *unbox<Dictionary *>(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
MonoObject *Array_to_system_generic_list(const Array &p_array, GDMonoClass *p_class, MonoReflectionType *p_elem_reftype) {
|
||||||
|
GDMonoClass *elem_class = ManagedType::from_reftype(p_elem_reftype).type_class;
|
||||||
|
|
||||||
|
String ctor_desc = ":.ctor(System.Collections.Generic.IEnumerable`1<" + elem_class->get_type_desc() + ">)";
|
||||||
|
GDMonoMethod *ctor = p_class->get_method_with_desc(ctor_desc, true);
|
||||||
|
CRASH_COND(ctor == nullptr);
|
||||||
|
|
||||||
|
MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr());
|
||||||
|
ERR_FAIL_NULL_V(mono_object, nullptr);
|
||||||
|
|
||||||
|
void *ctor_args[1] = { Array_to_mono_array(p_array, elem_class) };
|
||||||
|
|
||||||
|
MonoException *exc = nullptr;
|
||||||
|
ctor->invoke_raw(mono_object, ctor_args, &exc);
|
||||||
|
UNHANDLED_EXCEPTION(exc);
|
||||||
|
|
||||||
|
return mono_object;
|
||||||
|
}
|
||||||
|
|
||||||
|
Array system_generic_list_to_Array(MonoObject *p_obj, GDMonoClass *p_class, [[maybe_unused]] MonoReflectionType *p_elem_reftype) {
|
||||||
|
GDMonoMethod *to_array = p_class->get_method("ToArray", 0);
|
||||||
|
CRASH_COND(to_array == nullptr);
|
||||||
|
|
||||||
|
MonoException *exc = nullptr;
|
||||||
|
MonoArray *mono_array = (MonoArray *)to_array->invoke_raw(p_obj, nullptr, &exc);
|
||||||
|
UNHANDLED_EXCEPTION(exc);
|
||||||
|
|
||||||
|
return mono_array_to_Array(mono_array);
|
||||||
|
}
|
||||||
|
|
||||||
MonoArray *Array_to_mono_array(const Array &p_array) {
|
MonoArray *Array_to_mono_array(const Array &p_array) {
|
||||||
MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_array.size());
|
MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_array.size());
|
||||||
|
|
||||||
|
|
|
@ -122,6 +122,14 @@ Variant mono_object_to_variant_no_err(MonoObject *p_obj, const ManagedType &p_ty
|
||||||
/// If the MonoObject* cannot be converted to Variant, then 'ToString()' is called instead.
|
/// If the MonoObject* cannot be converted to Variant, then 'ToString()' is called instead.
|
||||||
String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc);
|
String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc);
|
||||||
|
|
||||||
|
// System.Collections.Generic
|
||||||
|
|
||||||
|
MonoObject *Dictionary_to_system_generic_dict(const Dictionary &p_dict, GDMonoClass *p_class, MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype);
|
||||||
|
Dictionary system_generic_dict_to_Dictionary(MonoObject *p_obj, GDMonoClass *p_class, MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype);
|
||||||
|
|
||||||
|
MonoObject *Array_to_system_generic_list(const Array &p_array, GDMonoClass *p_class, MonoReflectionType *p_elem_reftype);
|
||||||
|
Array system_generic_list_to_Array(MonoObject *p_obj, GDMonoClass *p_class, MonoReflectionType *p_elem_reftype);
|
||||||
|
|
||||||
// Array
|
// Array
|
||||||
|
|
||||||
MonoArray *Array_to_mono_array(const Array &p_array);
|
MonoArray *Array_to_mono_array(const Array &p_array);
|
||||||
|
|
|
@ -30,13 +30,14 @@
|
||||||
|
|
||||||
#include "gd_mono_method.h"
|
#include "gd_mono_method.h"
|
||||||
|
|
||||||
|
#include <mono/metadata/attrdefs.h>
|
||||||
|
#include <mono/metadata/debug-helpers.h>
|
||||||
|
|
||||||
#include "gd_mono_cache.h"
|
#include "gd_mono_cache.h"
|
||||||
#include "gd_mono_class.h"
|
#include "gd_mono_class.h"
|
||||||
#include "gd_mono_marshal.h"
|
#include "gd_mono_marshal.h"
|
||||||
#include "gd_mono_utils.h"
|
#include "gd_mono_utils.h"
|
||||||
|
|
||||||
#include <mono/metadata/attrdefs.h>
|
|
||||||
|
|
||||||
void GDMonoMethod::_update_signature() {
|
void GDMonoMethod::_update_signature() {
|
||||||
// Apparently MonoMethodSignature needs not to be freed.
|
// Apparently MonoMethodSignature needs not to be freed.
|
||||||
// mono_method_signature caches the result, we don't need to cache it ourselves.
|
// mono_method_signature caches the result, we don't need to cache it ourselves.
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include "gd_mono_utils.h"
|
#include "gd_mono_utils.h"
|
||||||
|
|
||||||
|
#include <mono/metadata/debug-helpers.h>
|
||||||
#include <mono/metadata/exception.h>
|
#include <mono/metadata/exception.h>
|
||||||
|
|
||||||
#include "core/os/dir_access.h"
|
#include "core/os/dir_access.h"
|
||||||
|
@ -322,6 +323,14 @@ MonoDomain *create_domain(const String &p_friendly_name) {
|
||||||
return domain;
|
return domain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String get_type_desc(MonoType *p_type) {
|
||||||
|
return mono_type_full_name(p_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
String get_type_desc(MonoReflectionType *p_reftype) {
|
||||||
|
return get_type_desc(mono_reflection_type_get_type(p_reftype));
|
||||||
|
}
|
||||||
|
|
||||||
String get_exception_name_and_message(MonoException *p_exc) {
|
String get_exception_name_and_message(MonoException *p_exc) {
|
||||||
String res;
|
String res;
|
||||||
|
|
||||||
|
@ -545,6 +554,46 @@ bool type_is_generic_dictionary(MonoReflectionType *p_reftype) {
|
||||||
return (bool)res;
|
return (bool)res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool type_is_system_generic_list(MonoReflectionType *p_reftype) {
|
||||||
|
NO_GLUE_RET(false);
|
||||||
|
MonoException *exc = NULL;
|
||||||
|
MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsSystemGenericList).invoke(p_reftype, &exc);
|
||||||
|
UNHANDLED_EXCEPTION(exc);
|
||||||
|
return (bool)res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool type_is_system_generic_dictionary(MonoReflectionType *p_reftype) {
|
||||||
|
NO_GLUE_RET(false);
|
||||||
|
MonoException *exc = NULL;
|
||||||
|
MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsSystemGenericDictionary).invoke(p_reftype, &exc);
|
||||||
|
UNHANDLED_EXCEPTION(exc);
|
||||||
|
return (bool)res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool type_is_generic_ienumerable(MonoReflectionType *p_reftype) {
|
||||||
|
NO_GLUE_RET(false);
|
||||||
|
MonoException *exc = NULL;
|
||||||
|
MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericIEnumerable).invoke(p_reftype, &exc);
|
||||||
|
UNHANDLED_EXCEPTION(exc);
|
||||||
|
return (bool)res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool type_is_generic_icollection(MonoReflectionType *p_reftype) {
|
||||||
|
NO_GLUE_RET(false);
|
||||||
|
MonoException *exc = NULL;
|
||||||
|
MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericICollection).invoke(p_reftype, &exc);
|
||||||
|
UNHANDLED_EXCEPTION(exc);
|
||||||
|
return (bool)res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool type_is_generic_idictionary(MonoReflectionType *p_reftype) {
|
||||||
|
NO_GLUE_RET(false);
|
||||||
|
MonoException *exc = NULL;
|
||||||
|
MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericIDictionary).invoke(p_reftype, &exc);
|
||||||
|
UNHANDLED_EXCEPTION(exc);
|
||||||
|
return (bool)res;
|
||||||
|
}
|
||||||
|
|
||||||
void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype) {
|
void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype) {
|
||||||
MonoException *exc = NULL;
|
MonoException *exc = NULL;
|
||||||
CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType).invoke(p_array_reftype, r_elem_reftype, &exc);
|
CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType).invoke(p_array_reftype, r_elem_reftype, &exc);
|
||||||
|
@ -557,65 +606,6 @@ void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoRefl
|
||||||
UNHANDLED_EXCEPTION(exc);
|
UNHANDLED_EXCEPTION(exc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype) {
|
|
||||||
NO_GLUE_RET(false);
|
|
||||||
MonoException *exc = NULL;
|
|
||||||
MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType).invoke(p_reftype, &exc);
|
|
||||||
UNHANDLED_EXCEPTION(exc);
|
|
||||||
return (bool)res;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype) {
|
|
||||||
NO_GLUE_RET(false);
|
|
||||||
MonoException *exc = NULL;
|
|
||||||
MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType).invoke(p_reftype, &exc);
|
|
||||||
UNHANDLED_EXCEPTION(exc);
|
|
||||||
return (bool)res;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_elem_reftype) {
|
|
||||||
NO_GLUE_RET(false);
|
|
||||||
MonoException *exc = NULL;
|
|
||||||
MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info).invoke(p_reftype, r_elem_reftype, &exc);
|
|
||||||
UNHANDLED_EXCEPTION(exc);
|
|
||||||
return (bool)res;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) {
|
|
||||||
NO_GLUE_RET(false);
|
|
||||||
MonoException *exc = NULL;
|
|
||||||
MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType_with_info).invoke(p_reftype, r_key_reftype, r_value_reftype, &exc);
|
|
||||||
UNHANDLED_EXCEPTION(exc);
|
|
||||||
return (bool)res;
|
|
||||||
}
|
|
||||||
|
|
||||||
Array enumerable_to_array(MonoObject *p_enumerable) {
|
|
||||||
NO_GLUE_RET(Array());
|
|
||||||
Array result;
|
|
||||||
MonoException *exc = NULL;
|
|
||||||
CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray).invoke(p_enumerable, &result, &exc);
|
|
||||||
UNHANDLED_EXCEPTION(exc);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dictionary idictionary_to_dictionary(MonoObject *p_idictionary) {
|
|
||||||
NO_GLUE_RET(Dictionary());
|
|
||||||
Dictionary result;
|
|
||||||
MonoException *exc = NULL;
|
|
||||||
CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary).invoke(p_idictionary, &result, &exc);
|
|
||||||
UNHANDLED_EXCEPTION(exc);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dictionary generic_idictionary_to_dictionary(MonoObject *p_generic_idictionary) {
|
|
||||||
NO_GLUE_RET(Dictionary());
|
|
||||||
Dictionary result;
|
|
||||||
MonoException *exc = NULL;
|
|
||||||
CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryToDictionary).invoke(p_generic_idictionary, &result, &exc);
|
|
||||||
UNHANDLED_EXCEPTION(exc);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
GDMonoClass *make_generic_array_type(MonoReflectionType *p_elem_reftype) {
|
GDMonoClass *make_generic_array_type(MonoReflectionType *p_elem_reftype) {
|
||||||
NO_GLUE_RET(NULL);
|
NO_GLUE_RET(NULL);
|
||||||
MonoException *exc = NULL;
|
MonoException *exc = NULL;
|
||||||
|
|
|
@ -53,22 +53,18 @@ namespace Marshal {
|
||||||
|
|
||||||
bool type_is_generic_array(MonoReflectionType *p_reftype);
|
bool type_is_generic_array(MonoReflectionType *p_reftype);
|
||||||
bool type_is_generic_dictionary(MonoReflectionType *p_reftype);
|
bool type_is_generic_dictionary(MonoReflectionType *p_reftype);
|
||||||
|
bool type_is_system_generic_list(MonoReflectionType *p_reftype);
|
||||||
|
bool type_is_system_generic_dictionary(MonoReflectionType *p_reftype);
|
||||||
|
bool type_is_generic_ienumerable(MonoReflectionType *p_reftype);
|
||||||
|
bool type_is_generic_icollection(MonoReflectionType *p_reftype);
|
||||||
|
bool type_is_generic_idictionary(MonoReflectionType *p_reftype);
|
||||||
|
|
||||||
void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype);
|
void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype);
|
||||||
void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype);
|
void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype);
|
||||||
|
|
||||||
bool generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype);
|
|
||||||
bool generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype);
|
|
||||||
bool generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_elem_reftype);
|
|
||||||
bool generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype);
|
|
||||||
|
|
||||||
GDMonoClass *make_generic_array_type(MonoReflectionType *p_elem_reftype);
|
GDMonoClass *make_generic_array_type(MonoReflectionType *p_elem_reftype);
|
||||||
GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype);
|
GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype);
|
||||||
|
|
||||||
Array enumerable_to_array(MonoObject *p_enumerable);
|
|
||||||
Dictionary idictionary_to_dictionary(MonoObject *p_idictionary);
|
|
||||||
Dictionary generic_idictionary_to_dictionary(MonoObject *p_generic_idictionary);
|
|
||||||
|
|
||||||
} // namespace Marshal
|
} // namespace Marshal
|
||||||
|
|
||||||
_FORCE_INLINE_ void hash_combine(uint32_t &p_hash, const uint32_t &p_with_hash) {
|
_FORCE_INLINE_ void hash_combine(uint32_t &p_hash, const uint32_t &p_with_hash) {
|
||||||
|
@ -108,6 +104,9 @@ MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class);
|
||||||
|
|
||||||
MonoDomain *create_domain(const String &p_friendly_name);
|
MonoDomain *create_domain(const String &p_friendly_name);
|
||||||
|
|
||||||
|
String get_type_desc(MonoType *p_type);
|
||||||
|
String get_type_desc(MonoReflectionType *p_reftype);
|
||||||
|
|
||||||
String get_exception_name_and_message(MonoException *p_exc);
|
String get_exception_name_and_message(MonoException *p_exc);
|
||||||
void set_exception_message(MonoException *p_exc, String message);
|
void set_exception_message(MonoException *p_exc, String message);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue