From 187e6ae26d88ab0975de6011d00e41a846bcb6fa Mon Sep 17 00:00:00 2001
From: Ignacio Etcheverry <ignalfonsore@gmail.com>
Date: Tue, 5 Mar 2019 18:52:19 +0100
Subject: C#: Add marshalling support for IEnumerable and IDictionary

Added constructor that takes IEnumerable for Array and IEnumerable<T> for Array<T>.
Added constructor that takes IDictionary for Dictionary and IDictionary<TKey, TValue> for Dictionary<TKey, TValue>.
---
 modules/mono/mono_gd/gd_mono_marshal.cpp | 92 +++++++++++++++++++++++++++-----
 1 file changed, 78 insertions(+), 14 deletions(-)

(limited to 'modules/mono/mono_gd/gd_mono_marshal.cpp')

diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index 7fe8ae608a..a522917b9e 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -156,14 +156,22 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
 			if (CACHED_CLASS(Array) == type_class) {
 				return Variant::ARRAY;
 			}
+
+			if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+				return Variant::DICTIONARY;
+			}
+
+			if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+				return Variant::ARRAY;
+			}
 		} break;
 
 		case MONO_TYPE_GENERICINST: {
 			MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_type.type_class->get_mono_type());
 
 			MonoException *exc = NULL;
-			GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
-			MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc);
+			GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
+			MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, &exc);
 			UNLIKELY_UNHANDLED_EXCEPTION(exc);
 
 			if (is_dict) {
@@ -171,13 +179,21 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
 			}
 
 			exc = NULL;
-			GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
-			MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc);
+			GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
+			MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, &exc);
 			UNLIKELY_UNHANDLED_EXCEPTION(exc);
 
 			if (is_array) {
 				return Variant::ARRAY;
 			}
+
+			if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+				return Variant::DICTIONARY;
+			}
+
+			if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+				return Variant::ARRAY;
+			}
 		} break;
 
 		default: {
@@ -453,6 +469,14 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
 			if (CACHED_CLASS(Array) == type_class) {
 				return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
 			}
+
+			if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+				return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
+			}
+
+			if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+				return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
+			}
 		} break;
 		case MONO_TYPE_OBJECT: {
 			// Variant
@@ -548,8 +572,8 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
 				MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_type.type_class->get_mono_type());
 
 				MonoException *exc = NULL;
-				GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
-				MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc);
+				GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
+				MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, &exc);
 				UNLIKELY_UNHANDLED_EXCEPTION(exc);
 
 				if (is_dict) {
@@ -557,13 +581,21 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
 				}
 
 				exc = NULL;
-				GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
-				MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc);
+				GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
+				MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, &exc);
 				UNLIKELY_UNHANDLED_EXCEPTION(exc);
 
 				if (is_array) {
 					return GDMonoUtils::create_managed_from(p_var->operator Array(), p_type.type_class);
 				}
+
+				if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+					return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
+				}
+
+				if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+					return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array));
+				}
 			} break;
 		} break;
 	}
@@ -717,17 +749,33 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
 
 			if (CACHED_CLASS(Array) == type_class) {
 				MonoException *exc = NULL;
-				Array *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Array, GetPtr), p_obj, (MonoObject **)&exc);
+				Array *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Array, GetPtr), p_obj, &exc);
 				UNLIKELY_UNHANDLED_EXCEPTION(exc);
 				return ptr ? Variant(*ptr) : Variant();
 			}
 
 			if (CACHED_CLASS(Dictionary) == type_class) {
 				MonoException *exc = NULL;
-				Dictionary *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Dictionary, GetPtr), p_obj, (MonoObject **)&exc);
+				Dictionary *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Dictionary, GetPtr), p_obj, &exc);
 				UNLIKELY_UNHANDLED_EXCEPTION(exc);
 				return ptr ? Variant(*ptr) : Variant();
 			}
+
+			if (type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+				Dictionary dict;
+				MonoException *exc = NULL;
+				invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary), p_obj, &dict, &exc);
+				UNLIKELY_UNHANDLED_EXCEPTION(exc);
+				return dict;
+			}
+
+			if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+				Array array;
+				MonoException *exc = NULL;
+				invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray), p_obj, &array, &exc);
+				UNLIKELY_UNHANDLED_EXCEPTION(exc);
+				return array;
+			}
 		} break;
 
 		case MONO_TYPE_GENERICINST: {
@@ -735,8 +783,8 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
 
 			MonoException *exc = NULL;
 
-			GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType);
-			MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, (MonoObject **)&exc);
+			GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
+			MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, &exc);
 			UNLIKELY_UNHANDLED_EXCEPTION(exc);
 
 			if (is_dict) {
@@ -748,8 +796,8 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
 
 			exc = NULL;
 
-			GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType);
-			MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, (MonoObject **)&exc);
+			GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
+			MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, &exc);
 			UNLIKELY_UNHANDLED_EXCEPTION(exc);
 
 			if (is_array) {
@@ -758,6 +806,22 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
 				UNLIKELY_UNHANDLED_EXCEPTION(exc);
 				return *unbox<Array *>(ret);
 			}
+
+			if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IDictionary))) {
+				Dictionary dict;
+				exc = NULL;
+				invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary), p_obj, &dict, &exc);
+				UNLIKELY_UNHANDLED_EXCEPTION(exc);
+				return dict;
+			}
+
+			if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) {
+				Array array;
+				exc = NULL;
+				invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray), p_obj, &array, &exc);
+				UNLIKELY_UNHANDLED_EXCEPTION(exc);
+				return array;
+			}
 		} break;
 	}
 
-- 
cgit v1.2.3


From 480d4c6fbabc65a0822cd3954e488bf64d04b45c Mon Sep 17 00:00:00 2001
From: Ignacio Etcheverry <ignalfonsore@gmail.com>
Date: Tue, 5 Mar 2019 21:39:50 +0100
Subject: C#: Support type hints for exported Arrays

Added the code for Dictionary as well, but it's not yet supported by the Godot inspector.
---
 modules/mono/mono_gd/gd_mono_marshal.cpp | 48 ++++++++++++++++++++++----------
 1 file changed, 33 insertions(+), 15 deletions(-)

(limited to 'modules/mono/mono_gd/gd_mono_marshal.cpp')

diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index a522917b9e..de4f3650bd 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -35,7 +35,7 @@
 
 namespace GDMonoMarshal {
 
-Variant::Type managed_to_variant_type(const ManagedType &p_type) {
+Variant::Type managed_to_variant_type(const ManagedType &p_type, ExportInfo *r_export_info) {
 	switch (p_type.type_encoding) {
 		case MONO_TYPE_BOOLEAN:
 			return Variant::BOOL;
@@ -171,19 +171,43 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) {
 
 			MonoException *exc = NULL;
 			GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
-			MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, &exc);
+			MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc);
 			UNLIKELY_UNHANDLED_EXCEPTION(exc);
 
 			if (is_dict) {
+				if (r_export_info) {
+					MonoReflectionType *key_reftype;
+					MonoReflectionType *value_reftype;
+
+					exc = NULL;
+					invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, DictionaryGetKeyValueTypes),
+							reftype, &key_reftype, &value_reftype, &exc);
+					UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+					r_export_info->dictionary.key_type = managed_to_variant_type(ManagedType::from_reftype(key_reftype));
+					r_export_info->dictionary.value_type = managed_to_variant_type(ManagedType::from_reftype(value_reftype));
+				}
+
 				return Variant::DICTIONARY;
 			}
 
 			exc = NULL;
 			GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
-			MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, &exc);
+			MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc);
 			UNLIKELY_UNHANDLED_EXCEPTION(exc);
 
 			if (is_array) {
+				if (r_export_info) {
+					MonoReflectionType *elem_reftype;
+
+					exc = NULL;
+					invoke_method_thunk(CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType),
+							reftype, &elem_reftype, &exc);
+					UNLIKELY_UNHANDLED_EXCEPTION(exc);
+
+					r_export_info->array.element_type = managed_to_variant_type(ManagedType::from_reftype(elem_reftype));
+				}
+
 				return Variant::ARRAY;
 			}
 
@@ -573,7 +597,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
 
 				MonoException *exc = NULL;
 				GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
-				MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, &exc);
+				MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc);
 				UNLIKELY_UNHANDLED_EXCEPTION(exc);
 
 				if (is_dict) {
@@ -582,7 +606,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
 
 				exc = NULL;
 				GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
-				MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, &exc);
+				MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc);
 				UNLIKELY_UNHANDLED_EXCEPTION(exc);
 
 				if (is_array) {
@@ -609,15 +633,9 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
 	if (!p_obj)
 		return Variant();
 
-	GDMonoClass *tclass = GDMono::get_singleton()->get_class(mono_object_get_class(p_obj));
-	ERR_FAIL_COND_V(!tclass, Variant());
-
-	MonoType *raw_type = tclass->get_mono_type();
-
-	ManagedType type;
+	ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj));
 
-	type.type_encoding = mono_type_get_type(raw_type);
-	type.type_class = tclass;
+	ERR_FAIL_COND_V(!type.type_class, Variant());
 
 	switch (type.type_encoding) {
 		case MONO_TYPE_BOOLEAN:
@@ -784,7 +802,7 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
 			MonoException *exc = NULL;
 
 			GDMonoUtils::TypeIsGenericDictionary type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary);
-			MonoBoolean is_dict = invoke_method_thunk(type_is_dict, (MonoObject *)reftype, &exc);
+			MonoBoolean is_dict = invoke_method_thunk(type_is_dict, reftype, &exc);
 			UNLIKELY_UNHANDLED_EXCEPTION(exc);
 
 			if (is_dict) {
@@ -797,7 +815,7 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
 			exc = NULL;
 
 			GDMonoUtils::TypeIsGenericArray type_is_array = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray);
-			MonoBoolean is_array = invoke_method_thunk(type_is_array, (MonoObject *)reftype, &exc);
+			MonoBoolean is_array = invoke_method_thunk(type_is_array, reftype, &exc);
 			UNLIKELY_UNHANDLED_EXCEPTION(exc);
 
 			if (is_array) {
-- 
cgit v1.2.3