// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #pragma once #include "MTypes.h" #include "Engine/Core/Types/StringView.h" #include "Engine/Core/Types/DataContainer.h" #include "Engine/Core/Types/Variant.h" #include "Engine/Scripting/ScriptingObject.h" #include #include namespace MUtils { extern FLAXENGINE_API StringView ToString(MonoString* str); extern FLAXENGINE_API StringAnsi ToStringAnsi(MonoString* str); extern FLAXENGINE_API void ToString(MonoString* str, String& result); extern FLAXENGINE_API void ToString(MonoString* str, StringView& result); extern FLAXENGINE_API void ToString(MonoString* str, Variant& result); extern FLAXENGINE_API void ToString(MonoString* str, MString& result); /// /// Converts unmanaged string text into managed string object. /// /// Text to convert. /// C# string. extern FLAXENGINE_API MonoString* ToString(const char* str); /// /// Converts unmanaged string text into managed string object. /// /// Text to convert. /// C# string. extern FLAXENGINE_API MonoString* ToString(const StringAnsi& str); /// /// Converts unmanaged string text into managed string object. /// /// Text to convert. /// C# string. extern FLAXENGINE_API MonoString* ToString(const String& str); /// /// Converts unmanaged string text into managed string object. /// /// Text to convert. /// The context domain. /// C# string. extern FLAXENGINE_API MonoString* ToString(const String& str, MonoDomain* domain); /// /// Converts unmanaged static string text into managed string object. /// /// Text to convert. /// C# string. extern FLAXENGINE_API MonoString* ToString(const StringAnsiView& str); /// /// Converts unmanaged static string text into managed string object. /// /// Text to convert. /// C# string. extern FLAXENGINE_API MonoString* ToString(const StringView& str); /// /// Converts unmanaged static string text into managed string object. /// /// Text to convert. /// The context domain. /// C# string. extern FLAXENGINE_API MonoString* ToString(const StringView& str, MonoDomain* domain); extern FLAXENGINE_API VariantType UnboxVariantType(MonoReflectionType* value); extern FLAXENGINE_API VariantType UnboxVariantType(MonoType* monoType); extern FLAXENGINE_API MonoReflectionType* BoxVariantType(const VariantType& value); extern FLAXENGINE_API Variant UnboxVariant(MonoObject* value); extern FLAXENGINE_API MonoObject* BoxVariant(const Variant& value); } // Converter for data of type T between managed and unmanaged world template struct MConverter { static_assert(fmt::internal::no_formatter_error::value, "Unsupported type for Scripting API."); MonoObject* Box(const T& data, MonoClass* klass); void Unbox(T& result, MonoObject* data); void ToManagedArray(MonoArray* result, const Span& data); template void ToNativeArray(Array& result, MonoArray* data, int32 length); }; // Converter for POD types (that can use raw memory copy). template struct MConverter, TNot::Type>>>::Value>::Type> { MonoObject* Box(const T& data, MonoClass* klass) { return mono_value_box(mono_domain_get(), klass, (void*)&data); } void Unbox(T& result, MonoObject* data) { CHECK(data); Platform::MemoryCopy(&result, mono_object_unbox(data), sizeof(T)); } void ToManagedArray(MonoArray* result, const Span& data) { Platform::MemoryCopy(mono_array_addr(result, T, 0), data.Get(), data.Length() * sizeof(T)); } template void ToNativeArray(Array& result, MonoArray* data, int32 length) { result.Add(mono_array_addr(data, T, 0), length); } }; // Converter for String. template<> struct MConverter { MonoObject* Box(const String& data, MonoClass* klass) { return (MonoObject*)MUtils::ToString(data); } void Unbox(String& result, MonoObject* data) { result = MUtils::ToString((MonoString*)data); } void ToManagedArray(MonoArray* result, const Span& data) { for (int32 i = 0; i < data.Length(); i++) mono_array_setref(result, i, MUtils::ToString(data[i])); } template void ToNativeArray(Array& result, MonoArray* data, int32 length) { result.Resize(length); for (int32 i = 0; i < length; i++) MUtils::ToString(mono_array_get(data, MonoString*, i), result[i]); } }; // Converter for StringView. template<> struct MConverter { MonoObject* Box(const StringView& data, MonoClass* klass) { return (MonoObject*)MUtils::ToString(data); } void Unbox(StringView& result, MonoObject* data) { result = MUtils::ToString((MonoString*)data); } void ToManagedArray(MonoArray* result, const Span& data) { for (int32 i = 0; i < data.Length(); i++) mono_array_setref(result, i, MUtils::ToString(data[i])); } template void ToNativeArray(Array& result, MonoArray* data, int32 length) { result.Resize(length); for (int32 i = 0; i < length; i++) MUtils::ToString(mono_array_get(data, MonoString*, i), result[i]); } }; // Converter for Variant. template<> struct MConverter { MonoObject* Box(const Variant& data, MonoClass* klass) { return MUtils::BoxVariant(data); } void Unbox(Variant& result, MonoObject* data) { result = MUtils::UnboxVariant(data); } void ToManagedArray(MonoArray* result, const Span& data) { for (int32 i = 0; i < data.Length(); i++) mono_array_setref(result, i, MUtils::BoxVariant(data[i])); } template void ToNativeArray(Array& result, MonoArray* data, int32 length) { result.Resize(length); for (int32 i = 0; i < length; i++) result[i] = MUtils::UnboxVariant(mono_array_get(data, MonoObject*, i)); } }; // Converter for Scripting Objects (collection of pointers). template struct MConverter::Value>::Type> { MonoObject* Box(T* data, MonoClass* klass) { return data ? data->GetOrCreateManagedInstance() : nullptr; } void Unbox(T*& result, MonoObject* data) { result = (T*)ScriptingObject::ToNative(data); } void ToManagedArray(MonoArray* result, const Span& data) { for (int32 i = 0; i < data.Length(); i++) { auto obj = data[i]; mono_array_setref(result, i, obj ? obj->GetOrCreateManagedInstance() : nullptr); } } template void ToNativeArray(Array& result, MonoArray* data, int32 length) { result.Resize(length); for (int32 i = 0; i < length; i++) result[i] = (T*)ScriptingObject::ToNative(mono_array_get(data, MonoObject*, i)); } }; // Converter for Scripting Objects (collection of values). template struct MConverter::Value>::Type> { MonoObject* Box(const T& data, MonoClass* klass) { return data.GetOrCreateManagedInstance(); } void Unbox(T& result, MonoObject* data) { // Not Supported CRASH; } void ToManagedArray(MonoArray* result, const Span& data) { for (int32 i = 0; i < data.Length(); i++) mono_array_setref(result, i, data[i].GetOrCreateManagedInstance()); } template void ToNativeArray(Array& result, MonoArray* data, int32 length) { // Not Supported CRASH; } }; // Converter for Asset References. template class AssetReference; template struct MConverter> { MonoObject* Box(const AssetReference& data, MonoClass* klass) { return data.GetManagedInstance(); } void Unbox(AssetReference& result, MonoObject* data) { result = (T*)ScriptingObject::ToNative(data); } void ToManagedArray(MonoArray* result, const Span>& data) { for (int32 i = 0; i < data.Length(); i++) mono_array_setref(result, i, data[i].GetManagedInstance()); } template void ToNativeArray(Array, AllocationType>& result, MonoArray* data, int32 length) { result.Resize(length); for (int32 i = 0; i < length; i++) result[i] = (T*)ScriptingObject::ToNative(mono_array_get(data, MonoObject*, i)); } }; namespace MUtils { // Outputs the full typename for the type of the specified object. extern FLAXENGINE_API void GetClassFullname(MonoObject* obj, MString& fullname); // Outputs the full typename for the specified type. extern FLAXENGINE_API void GetClassFullname(MonoClass* monoClass, MString& fullname); // Outputs the full typename for the specified type. extern FLAXENGINE_API void GetClassFullname(MonoReflectionType* type, MString& fullname); // Outputs the full typename for the type of the specified object. inline MString GetClassFullname(MonoObject* obj) { MString fullname; GetClassFullname(obj, fullname); return fullname; } // Outputs the full typename for the type of the specified object. inline MString GetClassFullname(MonoClass* monoClass) { MString fullname; GetClassFullname(monoClass, fullname); return fullname; } // Returns the class of the provided object. extern FLAXENGINE_API MonoClass* GetClass(MonoObject* object); // Returns the class of the provided type. extern FLAXENGINE_API MonoClass* GetClass(MonoReflectionType* type); // Returns the class of the provided VariantType value. extern FLAXENGINE_API MonoClass* GetClass(const VariantType& value); // Returns the class of the provided Variant value. extern FLAXENGINE_API MonoClass* GetClass(const Variant& value); // Returns the type of the provided object. extern FLAXENGINE_API MonoReflectionType* GetType(MonoObject* object); // Returns the type of the provided class. extern FLAXENGINE_API MonoReflectionType* GetType(MonoClass* klass); // Returns the type of the provided class. extern FLAXENGINE_API MonoReflectionType* GetType(MClass* mclass); /// /// Boxes the native value into the MonoObject. /// /// The value. /// The value type class. template MonoObject* Box(const T& value, MonoClass* valueClass) { MConverter converter; return converter.Box(value, valueClass); } /// /// Unboxes MonoObject to the native value of the given type. /// template T Unbox(MonoObject* object) { MConverter converter; T result; converter.Unbox(result, object); return result; } /// /// Links managed array data to the unmanaged BytesContainer. /// /// The array object. /// The result data container with linked array data bytes (not copied). extern FLAXENGINE_API BytesContainer LinkArray(MonoArray* arrayObj); /// /// Allocates new managed array of data and copies contents from given native array. /// /// The array object. /// The array values type class. /// The output array. template MonoArray* ToArray(const Span& data, MonoClass* valueClass) { if (!valueClass) return nullptr; // TODO: use shared empty arrays cache auto result = mono_array_new(mono_domain_get(), valueClass, data.Length()); MConverter converter; converter.ToManagedArray(result, data); return result; } /// /// Allocates new managed array of data and copies contents from given native array. /// /// The array object. /// The array values type class. /// The output array. template FORCE_INLINE MonoArray* ToArray(const Array& data, MonoClass* valueClass) { return MUtils::ToArray(Span(data.Get(), data.Count()), valueClass); } /// /// Converts the managed array into native array container object. /// /// The managed array object. /// The output array. template Array ToArray(MonoArray* arrayObj) { Array result; auto length = arrayObj ? (int32)mono_array_length(arrayObj) : 0; result.EnsureCapacity(length); MConverter converter; converter.ToNativeArray(result, arrayObj, length); return result; } /// /// Converts the managed array into native Span. /// /// The managed array object. /// The output array pointer and size. template Span ToSpan(MonoArray* arrayObj) { auto ptr = (T*)(void*)mono_array_addr_with_size(arrayObj, sizeof(T), 0); auto length = arrayObj ? (int32)mono_array_length(arrayObj) : 0; return Span(ptr, length); } /// /// Converts the native array into native Span. /// /// The native array object. /// The output array pointer and size. template FORCE_INLINE Span ToSpan(const Array& data) { return Span(data.Get(), data.Count()); } /// /// Links managed array data to the unmanaged DataContainer (must use simple type like struct or float/int/bool). /// /// The array object. /// The result data (linked not copied). template void ToArray(MonoArray* arrayObj, DataContainer& result) { auto length = arrayObj ? (int32)mono_array_length(arrayObj) : 0; if (length == 0) { result.Release(); return; } auto bytesRaw = (T*)(void*)mono_array_addr_with_size(arrayObj, sizeof(T), 0); result.Link(bytesRaw, length); } /// /// Allocates new managed bytes array and copies data from the given unmanaged data container. /// /// The input data. /// The output array. FORCE_INLINE MonoArray* ToArray(const Span& data) { return ToArray(data, mono_get_byte_class()); } /// /// Allocates new managed bytes array and copies data from the given unmanaged data container. /// /// The input data. /// The output array. FORCE_INLINE MonoArray* ToArray(Array& data) { return ToArray(Span(data.Get(), data.Count()), mono_get_byte_class()); } /// /// Allocates new managed strings array and copies data from the given unmanaged data container. /// /// The input data. /// The output array. FORCE_INLINE MonoArray* ToArray(const Span& data) { return ToArray(data, mono_get_string_class()); } /// /// Allocates new managed strings array and copies data from the given unmanaged data container. /// /// The input data. /// The output array. FORCE_INLINE MonoArray* ToArray(const Array& data) { return ToArray(Span(data.Get(), data.Count()), mono_get_string_class()); } extern void* VariantToManagedArgPtr(Variant& value, const MType& type, bool& failed); };