2017-11-05 10:37:59 +00:00
|
|
|
using System;
|
2019-03-05 17:52:19 +00:00
|
|
|
using System.Collections;
|
2019-05-18 02:14:21 +00:00
|
|
|
using System.Collections.Generic;
|
2017-10-02 21:24:00 +00:00
|
|
|
|
|
|
|
namespace Godot
|
|
|
|
{
|
2019-03-05 17:52:19 +00:00
|
|
|
using Array = Godot.Collections.Array;
|
|
|
|
using Dictionary = Godot.Collections.Dictionary;
|
|
|
|
|
2018-07-18 21:07:57 +00:00
|
|
|
static class MarshalUtils
|
2017-10-02 21:24:00 +00:00
|
|
|
{
|
2019-05-18 02:14:21 +00:00
|
|
|
/// <summary>
|
|
|
|
/// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
|
|
|
|
/// is <see cref="Godot.Collections.Array{T}"/>; otherwise returns <see langword="false"/>.
|
|
|
|
/// </summary>
|
|
|
|
/// <exception cref="System.InvalidOperationException">
|
|
|
|
/// <paramref name="type"/> is not a generic type. That is, IsGenericType returns false.
|
|
|
|
/// </exception>
|
2019-03-05 17:52:19 +00:00
|
|
|
static bool TypeIsGenericArray(Type type)
|
|
|
|
{
|
|
|
|
return type.GetGenericTypeDefinition() == typeof(Godot.Collections.Array<>);
|
|
|
|
}
|
|
|
|
|
2019-05-18 02:14:21 +00:00
|
|
|
/// <summary>
|
|
|
|
/// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
|
|
|
|
/// is <see cref="Godot.Collections.Dictionary{T}"/>; otherwise returns <see langword="false"/>.
|
|
|
|
/// </summary>
|
|
|
|
/// <exception cref="System.InvalidOperationException">
|
|
|
|
/// <paramref name="type"/> is not a generic type. That is, IsGenericType returns false.
|
|
|
|
/// </exception>
|
2019-03-05 17:52:19 +00:00
|
|
|
static bool TypeIsGenericDictionary(Type type)
|
|
|
|
{
|
|
|
|
return type.GetGenericTypeDefinition() == typeof(Godot.Collections.Dictionary<,>);
|
|
|
|
}
|
|
|
|
|
2019-05-18 02:14:21 +00:00
|
|
|
static void ArrayGetElementType(Type arrayType, out Type elementType)
|
2019-03-05 20:39:50 +00:00
|
|
|
{
|
2019-05-18 02:14:21 +00:00
|
|
|
elementType = arrayType.GetGenericArguments()[0];
|
2019-03-05 20:39:50 +00:00
|
|
|
}
|
|
|
|
|
2019-05-18 02:14:21 +00:00
|
|
|
static void DictionaryGetKeyValueTypes(Type dictionaryType, out Type keyType, out Type valueType)
|
2019-03-05 20:39:50 +00:00
|
|
|
{
|
2019-05-18 02:14:21 +00:00
|
|
|
var genericArgs = dictionaryType.GetGenericArguments();
|
2019-03-05 20:39:50 +00:00
|
|
|
keyType = genericArgs[0];
|
|
|
|
valueType = genericArgs[1];
|
|
|
|
}
|
|
|
|
|
2019-05-18 02:14:21 +00:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
return typeof(Godot.Collections.Array<>).MakeGenericType(elemType);
|
|
|
|
}
|
|
|
|
|
|
|
|
static Type MakeGenericDictionaryType(Type keyType, Type valueType)
|
|
|
|
{
|
|
|
|
return typeof(Godot.Collections.Dictionary<,>).MakeGenericType(keyType, valueType);
|
|
|
|
}
|
|
|
|
|
2019-03-05 20:39:50 +00:00
|
|
|
// TODO Add support for IEnumerable<T> and IDictionary<TKey, TValue>
|
2019-03-05 17:52:19 +00:00
|
|
|
// TODO: EnumerableToArray and IDictionaryToDictionary can be optimized
|
|
|
|
|
|
|
|
internal static void EnumerableToArray(IEnumerable enumerable, IntPtr godotArrayPtr)
|
2017-10-02 21:24:00 +00:00
|
|
|
{
|
2019-03-05 17:52:19 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2017-10-02 21:24:00 +00:00
|
|
|
}
|
|
|
|
|
2019-03-05 17:52:19 +00:00
|
|
|
internal static void IDictionaryToDictionary(IDictionary dictionary, IntPtr godotDictionaryPtr)
|
2017-10-02 21:24:00 +00:00
|
|
|
{
|
2019-03-05 17:52:19 +00:00
|
|
|
foreach (DictionaryEntry entry in dictionary)
|
|
|
|
{
|
|
|
|
Dictionary.godot_icall_Dictionary_Add(godotDictionaryPtr, entry.Key, entry.Value);
|
|
|
|
}
|
2017-10-02 21:24:00 +00:00
|
|
|
}
|
2019-05-18 02:14:21 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2017-10-02 21:24:00 +00:00
|
|
|
}
|
|
|
|
}
|