21 Commits

Author SHA1 Message Date
3008d8037d _unbox
Some checks failed
Build Android / Game (Android, Release ARM64) (push) Has been cancelled
Build iOS / Game (iOS, Release ARM64) (push) Has been cancelled
Build Linux / Editor (Linux, Development x64) (push) Has been cancelled
Build Linux / Game (Linux, Release x64) (push) Has been cancelled
Build macOS / Editor (Mac, Development ARM64) (push) Has been cancelled
Build macOS / Game (Mac, Release ARM64) (push) Has been cancelled
Build Windows / Editor (Windows, Development x64) (push) Has been cancelled
Build Windows / Game (Windows, Release x64) (push) Has been cancelled
Cooker / Cook (Mac) (push) Has been cancelled
Tests / Tests (Linux) (push) Has been cancelled
Tests / Tests (Windows) (push) Has been cancelled
2025-12-21 20:17:24 +02:00
0973363c64 wip 2 no leaks 2025-12-21 17:45:46 +02:00
5d45b9ea1c Fix managed boolean array conversion to native array 2025-12-20 01:51:37 +02:00
c40f7c12f2 Fix incorrect class namespace in bindings class name lookups 2025-12-19 23:57:31 +02:00
1b2d6372b2 Fix warnings 2025-12-19 13:16:35 +02:00
0782ea889c Fix command-line parsing for SDL CreateProcess arguments 2025-12-19 13:16:35 +02:00
ef89501111 Add function for parsing command-line arguments into argument list 2025-12-19 13:16:35 +02:00
608353b996 _managed handle pool start 2025-12-19 13:14:11 +02:00
221325ef09 _freemanaged dllexport used 2025-12-19 13:14:10 +02:00
8f57c91a9e _track disabled 2025-12-19 13:14:10 +02:00
968de34cae _wip 2025-12-19 13:14:10 +02:00
6586a98f8d Ensure managed converter functions are exported with optimizations 2025-12-19 13:14:10 +02:00
b3510b0e44 Add USED attribute for forcing compiler to emit the symbol 2025-12-19 13:14:10 +02:00
d5a92c1942 Fix missing exports for managed converter structures 2025-12-19 13:14:10 +02:00
417f82826f Expose RenderContext to scripting API 2025-12-19 13:14:10 +02:00
63bed0986a Fix clang bindings code generation for non-const ref parameters 2025-12-19 13:14:10 +02:00
c40eefc79d Fix compilation errors with /permissive- standard conformance mode 2025-12-19 13:14:10 +02:00
d68631dd20 Fix Editor project file generation to use custom code editor arguments 2025-12-19 13:14:10 +02:00
e77b772010 Get code editor name through CodeEditingManager 2025-12-19 13:14:10 +02:00
e41e956386 Fix default code editor not using Visual Studio as fallback editor 2025-12-19 13:14:10 +02:00
33e47c646b Fix invalid code editor when selected editor is not detected 2025-12-19 13:14:10 +02:00
17 changed files with 780 additions and 106 deletions

View File

@@ -397,7 +397,8 @@ bool ManagedEditor::HasGameViewportFocus() const
Internal_HasGameViewportFocus = GetClass()->GetMethod("Internal_HasGameViewportFocus"); Internal_HasGameViewportFocus = GetClass()->GetMethod("Internal_HasGameViewportFocus");
ASSERT(Internal_HasGameViewportFocus); ASSERT(Internal_HasGameViewportFocus);
} }
result = MUtils::Unbox<bool>(Internal_HasGameViewportFocus->Invoke(GetManagedInstance(), nullptr, nullptr), true); auto invk = Internal_HasGameViewportFocus->Invoke(GetManagedInstance(), nullptr, nullptr);
result = MUtils::Unbox<bool>(invk, true);
} }
return result; return result;
} }

View File

@@ -962,7 +962,7 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
else if (!MCore::Type::IsPointer(valueType) && !MCore::Type::IsReference(valueType)) else if (!MCore::Type::IsPointer(valueType) && !MCore::Type::IsReference(valueType))
{ {
if (boxed) if (boxed)
Platform::MemoryCopy(value, MCore::Object::Unbox(boxed), valueSize); MCore::Object::Unbox(boxed, value);
else else
Platform::MemoryClear(value, valueSize); Platform::MemoryClear(value, valueSize);
} }

View File

@@ -4301,8 +4301,12 @@ void Variant::CopyStructure(void* src)
if (MANAGED_GC_HANDLE && mclass->IsValueType()) if (MANAGED_GC_HANDLE && mclass->IsValueType())
{ {
MObject* instance = MCore::GCHandle::GetTarget(MANAGED_GC_HANDLE); MObject* instance = MCore::GCHandle::GetTarget(MANAGED_GC_HANDLE);
void* data = MCore::Object::Unbox(instance); PLATFORM_DEBUG_BREAK; // FIXME
Platform::MemoryCopy(data, src, mclass->GetInstanceSize()); MCore::GCHandle::Free(MANAGED_GC_HANDLE);
instance = MCore::Object::Box(src, mclass);
MANAGED_GC_HANDLE = *(MGCHandle*)&instance;
//void* data = MCore::Object::Unbox(instance);
//Platform::MemoryCopy(data, src, mclass->GetInstanceSize());
} }
} }
#endif #endif

View File

@@ -4,6 +4,7 @@
#include "Engine/Core/Types/String.h" #include "Engine/Core/Types/String.h"
#include "Engine/Core/Types/Nullable.h" #include "Engine/Core/Types/Nullable.h"
#include "Engine/Core/Collections/Array.h"
/// <summary> /// <summary>
/// Command line options helper. /// Command line options helper.

View File

@@ -2,7 +2,8 @@
#define USE_CONCURRENT_DICT #define USE_CONCURRENT_DICT
#define USE_GCHANDLE #define USE_GCHANDLE
#define TRACK_HANDLES //#define TRACK_HANDLES
#if USE_NETCORE #if USE_NETCORE
using System; using System;
@@ -351,6 +352,14 @@ namespace FlaxEngine.Interop
return; return;
handle.Free(); handle.Free();
} }
[System.Diagnostics.DebuggerStepThrough]
public static void Free(ManagedHandle handle)
{
if (handle == EmptyStringHandle)
return;
handle.Free();
}
} }
/// <summary> /// <summary>
@@ -373,6 +382,9 @@ namespace FlaxEngine.Interop
public static long Allocations => Interlocked.Read(ref _allocations); public static long Allocations => Interlocked.Read(ref _allocations);
public static long Deallocations => Interlocked.Read(ref _deallocations); public static long Deallocations => Interlocked.Read(ref _deallocations);
#else
public static long Allocations => 0;
public static long Deallocations => 0;
#endif #endif
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -382,14 +394,14 @@ namespace FlaxEngine.Interop
private ManagedHandle(object value, GCHandleType type) //=> handle = GCHandle.Alloc(value, type); private ManagedHandle(object value, GCHandleType type) //=> handle = GCHandle.Alloc(value, type);
{ {
#if TRACK_HANDLES #if TRACK_HANDLES
if (type == GCHandleType.Weak || type == GCHandleType.WeakTrackResurrection) /*if (type == GCHandleType.Weak || type == GCHandleType.WeakTrackResurrection)
{ {
type = GCHandleType.Normal; type = GCHandleType.Normal;
} }*/
#endif #endif
handle = GCHandle.Alloc(value, type); handle = GCHandle.Alloc(value, type);
#if TRACK_HANDLES #if TRACK_HANDLES
if (type == GCHandleType.Weak || type == GCHandleType.WeakTrackResurrection) /*if (type == GCHandleType.Weak || type == GCHandleType.WeakTrackResurrection)
_weakHandles.Add((IntPtr)handle); _weakHandles.Add((IntPtr)handle);
else if (_handles.Count < 14000) else if (_handles.Count < 14000)
_handles.TryAdd((IntPtr)handle, value?.GetType().FullName ?? ""); _handles.TryAdd((IntPtr)handle, value?.GetType().FullName ?? "");
@@ -400,7 +412,7 @@ namespace FlaxEngine.Interop
if (value?.GetType() == typeof(string)) if (value?.GetType() == typeof(string))
type = type; type = type;
_handles2.TryAdd((IntPtr)handle, value?.GetType().FullName ?? ""); _handles2.TryAdd((IntPtr)handle, value?.GetType().FullName ?? "");
} }*/
Interlocked.Increment(ref _allocations); Interlocked.Increment(ref _allocations);
#endif #endif
} }
@@ -424,7 +436,7 @@ namespace FlaxEngine.Interop
if ((IntPtr)handle == IntPtr.Zero) if ((IntPtr)handle == IntPtr.Zero)
return; return;
#if TRACK_HANDLES #if TRACK_HANDLES
if (_weakHandles.Remove((IntPtr)handle)) /*if (_weakHandles.Remove((IntPtr)handle))
{ {
if (!handle.IsAllocated) if (!handle.IsAllocated)
handle = handle; handle = handle;
@@ -437,7 +449,7 @@ namespace FlaxEngine.Interop
else if (_handles2.Remove((IntPtr)handle, out _)) else if (_handles2.Remove((IntPtr)handle, out _))
{ {
handle = handle; handle = handle;
} }*/
Interlocked.Increment(ref _deallocations); Interlocked.Increment(ref _deallocations);
#endif #endif
handle.Free(); handle.Free();

View File

@@ -545,6 +545,18 @@ namespace FlaxEngine.Interop
} }
} }
[UnmanagedCallersOnly]
internal static void FreeArray(ManagedHandle handle)
{
if (!handle.IsAllocated)
return;
ManagedArray managedArray = Unsafe.As<ManagedArray>(handle.Target);
if (managedArray.ElementType.IsValueType)
managedArray.Free();
else
managedArray.FreePooled();
}
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
internal static ManagedHandle GetArrayTypeFromElementType(ManagedHandle elementTypeHandle) internal static ManagedHandle GetArrayTypeFromElementType(ManagedHandle elementTypeHandle)
{ {
@@ -613,6 +625,12 @@ namespace FlaxEngine.Interop
return ManagedString.ToNative/*Weak*/(new string(text, 0, length, System.Text.Encoding.UTF8)); return ManagedString.ToNative/*Weak*/(new string(text, 0, length, System.Text.Encoding.UTF8));
} }
[UnmanagedCallersOnly]
internal static void FreeString(ManagedHandle handle)
{
ManagedString.Free(handle);
}
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
internal static ManagedHandle GetObjectType(ManagedHandle handle) internal static ManagedHandle GetObjectType(ManagedHandle handle)
{ {
@@ -656,8 +674,10 @@ namespace FlaxEngine.Interop
} }
/// <summary> /// <summary>
/// Creates a managed copy of the value, and stores it in a boxed reference. /// Creates a managed converted copy of the unmanaged value, and boxes it in a managed handle.
/// </summary> /// </summary>
/// <param name="typeHandle">A handle to class type.</param>
/// <param name="valuePtr">A pointer to unmanaged value.</param>
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
internal static ManagedHandle BoxValue(ManagedHandle typeHandle, IntPtr valuePtr) internal static ManagedHandle BoxValue(ManagedHandle typeHandle, IntPtr valuePtr)
{ {
@@ -667,16 +687,17 @@ namespace FlaxEngine.Interop
} }
/// <summary> /// <summary>
/// Returns the address of the boxed value type. /// Writes the unboxed converted value to given address.
/// </summary> /// </summary>
/// <param name="objectHandle">A handle to boxed object.</param>
/// <param name="destinationPtr">The destination address for unboxed value.</param>
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
internal static IntPtr UnboxValue(ManagedHandle handle) internal static void UnboxValue(ManagedHandle objectHandle, IntPtr destinationPtr)
{ {
object value = handle.Target; object value = objectHandle.Target;
Assert.IsNotNull(value, "Boxed value type can't be null.");
Type type = value.GetType(); Type type = value.GetType();
if (!type.IsValueType) MarshalToNative(objectHandle.Target, destinationPtr, type);
return ManagedHandle.ToIntPtr(handle);
return ValueTypeUnboxer.GetPointer(value, type);
} }
[UnmanagedCallersOnly] [UnmanagedCallersOnly]

View File

@@ -194,7 +194,8 @@ CultureInfo MUtils::ToNative(void* value)
if (lcidProperty && lcidProperty->GetGetMethod()) if (lcidProperty && lcidProperty->GetGetMethod())
{ {
MObject* lcidObj = lcidProperty->GetGetMethod()->Invoke(value, nullptr, nullptr); MObject* lcidObj = lcidProperty->GetGetMethod()->Invoke(value, nullptr, nullptr);
lcid = *(int32*)MCore::Object::Unbox(lcidObj); PLATFORM_DEBUG_BREAK;
MCore::Object::Unbox(lcidObj, &lcid);
} }
} }
#endif #endif

View File

@@ -409,8 +409,6 @@ int32 SDLPlatform::CreateProcess(CreateProcessSettings& settings)
for (auto iter = settings.Environment.Begin(); iter != settings.Environment.End(); ++iter) for (auto iter = settings.Environment.Begin(); iter != settings.Environment.End(); ++iter)
SDL_SetEnvironmentVariable(env, StringAnsi(iter->Key).Get(), StringAnsi(iter->Value).Get(), true); SDL_SetEnvironmentVariable(env, StringAnsi(iter->Key).Get(), StringAnsi(iter->Value).Get(), true);
SDL_PropertiesID props = SDL_CreateProperties();
#if PLATFORM_WINDOWS
// Parse argument list with possible quotes included // Parse argument list with possible quotes included
Array<StringAnsi> arguments; Array<StringAnsi> arguments;
arguments.Add(StringAnsi(settings.FileName)); arguments.Add(StringAnsi(settings.FileName));
@@ -424,18 +422,14 @@ int32 SDLPlatform::CreateProcess(CreateProcessSettings& settings)
cmd.Add(str.Get()); cmd.Add(str.Get());
cmd.Add((const char*)0); cmd.Add((const char*)0);
SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, cmd.Get());
#else
const char* cmd[] = { "sh", "-c", cmdLine.Get(), (char*)0 };
SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, cmd);
#endif
#if PLATFORM_WINDOWS #if PLATFORM_WINDOWS
bool background = !settings.WaitForEnd || settings.HiddenWindow; // This also hides the window on Windows bool background = !settings.WaitForEnd || settings.HiddenWindow; // This also hides the window on Windows
#else #else
bool background = !settings.WaitForEnd; bool background = !settings.WaitForEnd;
#endif #endif
SDL_PropertiesID props = SDL_CreateProperties();
SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, cmd.Get());
SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ENVIRONMENT_POINTER, env); SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ENVIRONMENT_POINTER, env);
SDL_SetBooleanProperty(props, SDL_PROP_PROCESS_CREATE_BACKGROUND_BOOLEAN, background); SDL_SetBooleanProperty(props, SDL_PROP_PROCESS_CREATE_BACKGROUND_BOOLEAN, background);
if (workingDirectory.HasChars()) if (workingDirectory.HasChars())

View File

@@ -69,6 +69,7 @@ public:
{ {
static MObject* Box(void* value, const MClass* klass); static MObject* Box(void* value, const MClass* klass);
static void* Unbox(MObject* obj); static void* Unbox(MObject* obj);
static void Unbox(MObject* obj, void* dest);
static MObject* New(const MClass* klass); static MObject* New(const MClass* klass);
static void Init(MObject* obj); static void Init(MObject* obj);
static MClass* GetClass(MObject* obj); static MClass* GetClass(MObject* obj);
@@ -84,6 +85,7 @@ public:
static MString* GetEmpty(MDomain* domain = nullptr); static MString* GetEmpty(MDomain* domain = nullptr);
static MString* New(const char* str, int32 length, MDomain* domain = nullptr); static MString* New(const char* str, int32 length, MDomain* domain = nullptr);
static MString* New(const Char* str, int32 length, MDomain* domain = nullptr); static MString* New(const Char* str, int32 length, MDomain* domain = nullptr);
static void Free(MString* obj);
static StringView GetChars(MString* obj); static StringView GetChars(MString* obj);
}; };
@@ -93,6 +95,7 @@ public:
struct FLAXENGINE_API Array struct FLAXENGINE_API Array
{ {
static MArray* New(const MClass* elementKlass, int32 length); static MArray* New(const MClass* elementKlass, int32 length);
static void Free(const MArray* array);
static MClass* GetClass(MClass* elementKlass); static MClass* GetClass(MClass* elementKlass);
static MClass* GetArrayClass(const MArray* obj); static MClass* GetArrayClass(const MArray* obj);
static int32 GetLength(const MArray* obj); static int32 GetLength(const MArray* obj);

View File

@@ -313,7 +313,10 @@ Variant MUtils::UnboxVariant(MObject* value, bool releaseHandle)
MType* mType = klass->GetType(); MType* mType = klass->GetType();
const MTypes mTypes = MCore::Type::GetType(mType); const MTypes mTypes = MCore::Type::GetType(mType);
void* unboxed = MCore::Object::Unbox(value);
Variant storage;
MCore::Object::Unbox(value, &storage.AsData);
void* unboxed = &storage.AsData;
// Fast type detection for in-built types // Fast type detection for in-built types
switch (mTypes) switch (mTypes)
@@ -492,13 +495,16 @@ Variant MUtils::UnboxVariant(MObject* value, bool releaseHandle)
// TODO: optimize this for large arrays to prevent multiple AllocStructure calls in Variant::SetType by using computed struct type // TODO: optimize this for large arrays to prevent multiple AllocStructure calls in Variant::SetType by using computed struct type
for (int32 i = 0; i < array.Count(); i++) for (int32 i = 0; i < array.Count(); i++)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
auto& a = array[i]; auto& a = array[i];
a.SetType(elementType); a.SetType(elementType);
void* managed = (byte*)ptr + elementSize * i; void* managed = (byte*)ptr + elementSize * i;
// TODO: optimize structures unboxing to not require MObject* but raw managed value data to prevent additional boxing here // TODO: optimize structures unboxing to not require MObject* but raw managed value data to prevent additional boxing here
MObject* boxed = MCore::Object::New(elementClass); //MObject* boxed = MCore::Object::New(elementClass);
Platform::MemoryCopy(MCore::Object::Unbox(boxed), managed, elementSize); //Variant storage;
type.Struct.Unbox(a.AsBlob.Data, boxed); MCore::Object::Unbox((MObject*)managed, &a.AsBlob.Data);
//Platform::MemoryCopy(MCore::Object::Unbox(boxed), managed, elementSize);
//type.Struct.Unbox(a.AsBlob.Data, boxed);
} }
break; break;
} }
@@ -559,7 +565,8 @@ Variant MUtils::UnboxVariant(MObject* value, bool releaseHandle)
Variant v; Variant v;
v.Type = MoveTemp(VariantType(VariantType::Enum, fullname)); v.Type = MoveTemp(VariantType(VariantType::Enum, fullname));
// TODO: what about 64-bit enum? use enum size with memcpy // TODO: what about 64-bit enum? use enum size with memcpy
v.AsUint64 = *static_cast<uint32*>(MCore::Object::Unbox(value)); PLATFORM_DEBUG_BREAK; // FIXME
MCore::Object::Unbox(value, &v.AsUint64);
if (releaseHandle) if (releaseHandle)
MUtils::FreeManaged<byte>(value); MUtils::FreeManaged<byte>(value);
return v; return v;
@@ -743,9 +750,10 @@ MObject* MUtils::BoxVariant(const Variant& value)
ASSERT(type.Type == ScriptingTypes::Structure); ASSERT(type.Type == ScriptingTypes::Structure);
for (int32 i = 0; i < array.Count(); i++) for (int32 i = 0; i < array.Count(); i++)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
// TODO: optimize structures boxing to not return MObject* but use raw managed object to prevent additional boxing here // TODO: optimize structures boxing to not return MObject* but use raw managed object to prevent additional boxing here
MObject* boxed = type.Struct.Box(array[i].AsBlob.Data); MObject* boxed = type.Struct.Box(array[i].AsBlob.Data);
Platform::MemoryCopy(managedPtr + elementSize * i, MCore::Object::Unbox(boxed), elementSize); MCore::Object::Unbox(boxed, managedPtr + elementSize * i);
} }
break; break;
} }
@@ -1176,7 +1184,9 @@ void* MUtils::VariantToManagedArgPtr(Variant& value, MType* type, bool& failed)
auto& valueType = typeHandle.GetType(); auto& valueType = typeHandle.GetType();
if (valueType.ManagedClass == MCore::Type::GetClass(type)) if (valueType.ManagedClass == MCore::Type::GetClass(type))
{ {
return MCore::Object::Unbox(valueType.Struct.Box(value.AsBlob.Data)); PLATFORM_DEBUG_BREAK; // FIXME
MCore::Object::Unbox(valueType.Struct.Box(value.AsBlob.Data), &value.AsBlob.Data);
return &value.AsBlob.Data;
} }
LOG(Error, "Cannot marshal argument of type {0} as {1}", String(valueType.Fullname), MCore::Type::ToString(type)); LOG(Error, "Cannot marshal argument of type {0} as {1}", String(valueType.Fullname), MCore::Type::ToString(type));
} }
@@ -1187,9 +1197,11 @@ void* MUtils::VariantToManagedArgPtr(Variant& value, MType* type, bool& failed)
const ScriptingTypeHandle typeHandle = Scripting::FindScriptingType(fullname); const ScriptingTypeHandle typeHandle = Scripting::FindScriptingType(fullname);
if (typeHandle) if (typeHandle)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
auto& valueType = typeHandle.GetType(); auto& valueType = typeHandle.GetType();
value.SetType(VariantType(VariantType::Structure, fullname)); value.SetType(VariantType(VariantType::Structure, fullname));
return MCore::Object::Unbox(valueType.Struct.Box(value.AsBlob.Data)); MCore::Object::Unbox(valueType.Struct.Box(value.AsBlob.Data), &value.AsBlob.Data);
return &value.AsBlob.Data;
} }
} }
} }

View File

@@ -49,9 +49,18 @@ struct MConverter
{ {
MObject* Box(const T& data, const MClass* klass); MObject* Box(const T& data, const MClass* klass);
void Unbox(T& result, MObject* data); void Unbox(T& result, MObject* data);
void FreeManaged(MObject* data);
void ToManagedArray(MArray* result, const Span<T>& data); void ToManagedArray(MArray* result, const Span<T>& data);
void ToNativeArray(Span<T>& result, const MArray* data); void ToNativeArray(Span<T>& result, const MArray* data);
void FreeManaged(MObject* data); void FreeManagedArray(MArray* array);
};
// Simple array used to pass arrays of blittable data between managed and unmanaged side.
template<typename T>
struct NativeArray
{
T* data;
int32 length;
}; };
#if USE_NETCORE #if USE_NETCORE
@@ -67,7 +76,11 @@ struct MConverter<bool>
void Unbox(bool& result, MObject* data) void Unbox(bool& result, MObject* data)
{ {
if (data) if (data)
Platform::MemoryCopy(&result, MCore::Object::Unbox(data), sizeof(bool)); MCore::Object::Unbox(data, &result);
}
void FreeManaged(MObject* data)
{
} }
void ToManagedArray(MArray* result, const Span<bool>& data) void ToManagedArray(MArray* result, const Span<bool>& data)
@@ -80,8 +93,10 @@ struct MConverter<bool>
Platform::MemoryCopy(result.Get(), MCore::Array::GetAddress(data), result.Length() * sizeof(bool)); Platform::MemoryCopy(result.Get(), MCore::Array::GetAddress(data), result.Length() * sizeof(bool));
} }
void FreeManaged(MObject* data) void FreeManagedArray(MArray* array)
{ {
MCore::Array::Free(array);
MCore::GCHandle::Free(*(MGCHandle*)&array);
} }
}; };
#endif #endif
@@ -98,7 +113,7 @@ struct MConverter<T, typename TEnableIf<TAnd<TIsPODType<T>, TNot<TIsBaseOf<class
void Unbox(T& result, MObject* data) void Unbox(T& result, MObject* data)
{ {
if (data) if (data)
Platform::MemoryCopy(&result, MCore::Object::Unbox(data), sizeof(T)); MCore::Object::Unbox(data, &result);
} }
void ToManagedArray(MArray* result, const Span<T>& data) void ToManagedArray(MArray* result, const Span<T>& data)
@@ -115,6 +130,12 @@ struct MConverter<T, typename TEnableIf<TAnd<TIsPODType<T>, TNot<TIsBaseOf<class
{ {
MCore::GCHandle::Free(*(MGCHandle*)&data); MCore::GCHandle::Free(*(MGCHandle*)&data);
} }
void FreeManagedArray(MArray* array)
{
MCore::Array::Free(array);
MCore::GCHandle::Free(*(MGCHandle*)&array);
}
}; };
// Converter for String. // Converter for String.
@@ -163,7 +184,17 @@ struct MConverter<String>
{ {
//MString* str = (MString*)MCore::Object::Unbox(data); //MString* str = (MString*)MCore::Object::Unbox(data);
//MCore::GCHandle::Free(*(MGCHandle*)&str); //MCore::GCHandle::Free(*(MGCHandle*)&str);
MCore::GCHandle::Free(*(MGCHandle*)&data); MCore::String::Free((MString*)data);
}
void FreeManagedArray(MArray* array)
{
MString** dataPtr = MCore::Array::GetAddress<MString*>(array);
auto length = MCore::Array::GetLength(array);
for (int32 i = 0; i < length; i++)
MCore::String::Free(dataPtr[i]);
MCore::Array::Free(array);
MCore::GCHandle::Free(*(MGCHandle*)&array);
} }
}; };
@@ -201,7 +232,17 @@ struct MConverter<StringAnsi>
void FreeManaged(MObject* data) void FreeManaged(MObject* data)
{ {
MCore::GCHandle::Free(*(MGCHandle*)&data); MCore::String::Free((MString*)data);
}
void FreeManagedArray(MArray* array)
{
MString** dataPtr = MCore::Array::GetAddress<MString*>(array);
auto length = MCore::Array::GetLength(array);
for (int32 i = 0; i < length; i++)
MCore::String::Free(dataPtr[i]);
MCore::Array::Free(array);
MCore::GCHandle::Free(*(MGCHandle*)&array);
} }
}; };
@@ -211,16 +252,19 @@ struct MConverter<StringView>
{ {
MObject* Box(const StringView& data, const MClass* klass) MObject* Box(const StringView& data, const MClass* klass)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
return (MObject*)MUtils::ToString(data); return (MObject*)MUtils::ToString(data);
} }
void Unbox(StringView& result, MObject* data) void Unbox(StringView& result, MObject* data)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
result = MUtils::ToString((MString*)data); result = MUtils::ToString((MString*)data);
} }
void ToManagedArray(MArray* result, const Span<StringView>& data) void ToManagedArray(MArray* result, const Span<StringView>& data)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
if (data.Length() == 0) if (data.Length() == 0)
return; return;
MObject** objects = (MObject**)Allocator::Allocate(data.Length() * sizeof(MObject*)); MObject** objects = (MObject**)Allocator::Allocate(data.Length() * sizeof(MObject*));
@@ -232,6 +276,7 @@ struct MConverter<StringView>
void ToNativeArray(Span<StringView>& result, const MArray* data) void ToNativeArray(Span<StringView>& result, const MArray* data)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
MString** dataPtr = MCore::Array::GetAddress<MString*>(data); MString** dataPtr = MCore::Array::GetAddress<MString*>(data);
for (int32 i = 0; i < result.Length(); i++) for (int32 i = 0; i < result.Length(); i++)
MUtils::ToString(dataPtr[i], result.Get()[i]); MUtils::ToString(dataPtr[i], result.Get()[i]);
@@ -239,7 +284,19 @@ struct MConverter<StringView>
void FreeManaged(MObject* data) void FreeManaged(MObject* data)
{ {
MCore::GCHandle::Free(*(MGCHandle*)&data); PLATFORM_DEBUG_BREAK; // FIXME
MCore::String::Free((MString*)data);
}
void FreeManagedArray(MArray* array)
{
PLATFORM_DEBUG_BREAK; // FIXME
MString** dataPtr = MCore::Array::GetAddress<MString*>(array);
auto length = MCore::Array::GetLength(array);
for (int32 i = 0; i < length; i++)
MCore::String::Free(dataPtr[i]);
MCore::Array::Free(array);
MCore::GCHandle::Free(*(MGCHandle*)&array);
} }
}; };
@@ -249,16 +306,19 @@ struct MConverter<Variant>
{ {
MObject* Box(const Variant& data, const MClass* klass) MObject* Box(const Variant& data, const MClass* klass)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
return MUtils::BoxVariant(data); return MUtils::BoxVariant(data);
} }
void Unbox(Variant& result, MObject* data) void Unbox(Variant& result, MObject* data)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
result = MUtils::UnboxVariant(data); result = MUtils::UnboxVariant(data);
} }
void ToManagedArray(MArray* result, const Span<Variant>& data) void ToManagedArray(MArray* result, const Span<Variant>& data)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
if (data.Length() == 0) if (data.Length() == 0)
return; return;
MObject** objects = (MObject**)Allocator::Allocate(data.Length() * sizeof(MObject*)); MObject** objects = (MObject**)Allocator::Allocate(data.Length() * sizeof(MObject*));
@@ -270,6 +330,7 @@ struct MConverter<Variant>
void ToNativeArray(Span<Variant>& result, const MArray* data) void ToNativeArray(Span<Variant>& result, const MArray* data)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
MObject** dataPtr = MCore::Array::GetAddress<MObject*>(data); MObject** dataPtr = MCore::Array::GetAddress<MObject*>(data);
for (int32 i = 0; i < result.Length(); i++) for (int32 i = 0; i < result.Length(); i++)
result.Get()[i] = MUtils::UnboxVariant(dataPtr[i]); result.Get()[i] = MUtils::UnboxVariant(dataPtr[i]);
@@ -277,6 +338,14 @@ struct MConverter<Variant>
void FreeManaged(MObject* data) void FreeManaged(MObject* data)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
}
void FreeManagedArray(MArray* array)
{
PLATFORM_DEBUG_BREAK; // FIXME
MCore::Array::Free(array);
MCore::GCHandle::Free(*(MGCHandle*)&array);
} }
}; };
@@ -286,11 +355,13 @@ struct MConverter<T*, typename TEnableIf<TIsBaseOf<class ScriptingObject, T>::Va
{ {
MObject* Box(T* data, const MClass* klass) MObject* Box(T* data, const MClass* klass)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
return data ? data->GetOrCreateManagedInstance() : nullptr; return data ? data->GetOrCreateManagedInstance() : nullptr;
} }
void Unbox(T*& result, MObject* data) void Unbox(T*& result, MObject* data)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
result = (T*)ScriptingObject::ToNative(data); result = (T*)ScriptingObject::ToNative(data);
} }
@@ -314,6 +385,13 @@ struct MConverter<T*, typename TEnableIf<TIsBaseOf<class ScriptingObject, T>::Va
void FreeManaged(MObject* data) void FreeManaged(MObject* data)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
}
void FreeManagedArray(MArray* array)
{
MCore::Array::Free(array);
MCore::GCHandle::Free(*(MGCHandle*)&array);
} }
}; };
@@ -323,11 +401,13 @@ struct MConverter<T, typename TEnableIf<TIsBaseOf<class ScriptingObject, T>::Val
{ {
MObject* Box(const T& data, const MClass* klass) MObject* Box(const T& data, const MClass* klass)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
return data.GetOrCreateManagedInstance(); return data.GetOrCreateManagedInstance();
} }
void ToManagedArray(MArray* result, const Span<T>& data) void ToManagedArray(MArray* result, const Span<T>& data)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
if (data.Length() == 0) if (data.Length() == 0)
return; return;
MObject** objects = (MObject**)Allocator::Allocate(data.Length() * sizeof(MObject*)); MObject** objects = (MObject**)Allocator::Allocate(data.Length() * sizeof(MObject*));
@@ -339,6 +419,14 @@ struct MConverter<T, typename TEnableIf<TIsBaseOf<class ScriptingObject, T>::Val
void FreeManaged(MObject* data) void FreeManaged(MObject* data)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
}
void FreeManagedArray(MArray* array)
{
PLATFORM_DEBUG_BREAK; // FIXME
MCore::Array::Free(array);
MCore::GCHandle::Free(*(MGCHandle*)&array);
} }
}; };
@@ -351,16 +439,19 @@ struct MConverter<ScriptingObjectReference<T>>
{ {
MObject* Box(const ScriptingObjectReference<T>& data, const MClass* klass) MObject* Box(const ScriptingObjectReference<T>& data, const MClass* klass)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
return data.GetManagedInstance(); return data.GetManagedInstance();
} }
void Unbox(ScriptingObjectReference<T>& result, MObject* data) void Unbox(ScriptingObjectReference<T>& result, MObject* data)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
result = (T*)ScriptingObject::ToNative(data); result = (T*)ScriptingObject::ToNative(data);
} }
void ToManagedArray(MArray* result, const Span<ScriptingObjectReference<T>>& data) void ToManagedArray(MArray* result, const Span<ScriptingObjectReference<T>>& data)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
if (data.Length() == 0) if (data.Length() == 0)
return; return;
MObject** objects = (MObject**)Allocator::Allocate(data.Length() * sizeof(MObject*)); MObject** objects = (MObject**)Allocator::Allocate(data.Length() * sizeof(MObject*));
@@ -372,6 +463,7 @@ struct MConverter<ScriptingObjectReference<T>>
void ToNativeArray(Span<ScriptingObjectReference<T>>& result, const MArray* data) void ToNativeArray(Span<ScriptingObjectReference<T>>& result, const MArray* data)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
MObject** dataPtr = MCore::Array::GetAddress<MObject*>(data); MObject** dataPtr = MCore::Array::GetAddress<MObject*>(data);
for (int32 i = 0; i < result.Length(); i++) for (int32 i = 0; i < result.Length(); i++)
result.Get()[i] = (T*)ScriptingObject::ToNative(dataPtr[i]); result.Get()[i] = (T*)ScriptingObject::ToNative(dataPtr[i]);
@@ -379,6 +471,14 @@ struct MConverter<ScriptingObjectReference<T>>
void FreeManaged(MObject* data) void FreeManaged(MObject* data)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
}
void FreeManagedArray(MArray* array)
{
PLATFORM_DEBUG_BREAK; // FIXME
MCore::Array::Free(array);
MCore::GCHandle::Free(*(MGCHandle*)&array);
} }
}; };
@@ -391,11 +491,13 @@ struct MConverter<AssetReference<T>>
{ {
MObject* Box(const AssetReference<T>& data, const MClass* klass) MObject* Box(const AssetReference<T>& data, const MClass* klass)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
return data.GetManagedInstance(); return data.GetManagedInstance();
} }
void Unbox(AssetReference<T>& result, MObject* data) void Unbox(AssetReference<T>& result, MObject* data)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
result = (T*)ScriptingObject::ToNative(data); result = (T*)ScriptingObject::ToNative(data);
} }
@@ -412,6 +514,7 @@ struct MConverter<AssetReference<T>>
void ToNativeArray(Span<AssetReference<T>>& result, const MArray* data) void ToNativeArray(Span<AssetReference<T>>& result, const MArray* data)
{ {
//PLATFORM_DEBUG_BREAK; // FIXME
MObject** dataPtr = MCore::Array::GetAddress<MObject*>(data); MObject** dataPtr = MCore::Array::GetAddress<MObject*>(data);
for (int32 i = 0; i < result.Length(); i++) for (int32 i = 0; i < result.Length(); i++)
result.Get()[i] = (T*)ScriptingObject::ToNative(dataPtr[i]); result.Get()[i] = (T*)ScriptingObject::ToNative(dataPtr[i]);
@@ -419,6 +522,13 @@ struct MConverter<AssetReference<T>>
void FreeManaged(MObject* data) void FreeManaged(MObject* data)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
}
void FreeManagedArray(MArray* array)
{
MCore::Array::Free(array);
MCore::GCHandle::Free(*(MGCHandle*)&array);
} }
}; };
@@ -430,6 +540,7 @@ struct MConverter<SoftAssetReference<T>>
{ {
void ToManagedArray(MArray* result, const Span<SoftAssetReference<T>>& data) void ToManagedArray(MArray* result, const Span<SoftAssetReference<T>>& data)
{ {
//PLATFORM_DEBUG_BREAK; // FIXME
if (data.Length() == 0) if (data.Length() == 0)
return; return;
MObject** objects = (MObject**)Allocator::Allocate(data.Length() * sizeof(MObject*)); MObject** objects = (MObject**)Allocator::Allocate(data.Length() * sizeof(MObject*));
@@ -441,6 +552,7 @@ struct MConverter<SoftAssetReference<T>>
void ToNativeArray(Span<SoftAssetReference<T>>& result, const MArray* data) void ToNativeArray(Span<SoftAssetReference<T>>& result, const MArray* data)
{ {
//PLATFORM_DEBUG_BREAK; // FIXME
MObject** dataPtr = MCore::Array::GetAddress<MObject*>(data); MObject** dataPtr = MCore::Array::GetAddress<MObject*>(data);
for (int32 i = 0; i < result.Length(); i++) for (int32 i = 0; i < result.Length(); i++)
result.Get()[i] = (T*)ScriptingObject::ToNative(dataPtr[i]); result.Get()[i] = (T*)ScriptingObject::ToNative(dataPtr[i]);
@@ -448,6 +560,14 @@ struct MConverter<SoftAssetReference<T>>
void FreeManaged(MObject* data) void FreeManaged(MObject* data)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
}
void FreeManagedArray(MArray* array)
{
PLATFORM_DEBUG_BREAK; // FIXME
MCore::Array::Free(array);
MCore::GCHandle::Free(*(MGCHandle*)&array);
} }
}; };
@@ -457,6 +577,7 @@ struct MConverter<Array<T>>
{ {
MObject* Box(const Array<T>& data, const MClass* klass) MObject* Box(const Array<T>& data, const MClass* klass)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
if (!klass) if (!klass)
return nullptr; return nullptr;
MArray* result = MCore::Array::New(klass->GetElementClass(), data.Count()); MArray* result = MCore::Array::New(klass->GetElementClass(), data.Count());
@@ -477,6 +598,19 @@ struct MConverter<Array<T>>
void FreeManaged(MObject* data) void FreeManaged(MObject* data)
{ {
PLATFORM_DEBUG_BREAK; // FIXME
MArray* array = (MArray*)data;
MConverter<T> converter;
converter.FreeManagedArray(array);
//MCore::Array::Free(array);
//MCore::GCHandle::Free(*(MGCHandle*)&data);
}
void FreeManagedArray(MArray* array)
{
PLATFORM_DEBUG_BREAK; // FIXME
MCore::Array::Free(array);
MCore::GCHandle::Free(*(MGCHandle*)&array);
} }
}; };
@@ -544,6 +678,35 @@ namespace MUtils
return result; return result;
} }
/// <summary>
/// Unboxes MObject to the native value of the given type.
/// </summary>
///
template<>
inline bool Unbox(MObject* object)
{
MConverter<bool> converter;
int32 result;
converter.Unbox(*(bool*)&result, object);
return result != 0;
}
/// <summary>
/// Unboxes MObject to the native value of the given type.
/// </summary>
/// <param name="object">The object.</param>
/// <param name="releaseHandle">True if boxed managed handle should be released.</param>
template<>
inline bool Unbox(MObject* object, bool releaseHandle)
{
MConverter<bool> converter;
int32 result;
converter.Unbox(*(bool*)&result, object);
if (releaseHandle)
converter.FreeManaged(object);
return result != 0;
}
/// <summary> /// <summary>
/// Releases the managed resources of a boxed object. /// Releases the managed resources of a boxed object.
/// </summary> /// </summary>
@@ -554,6 +717,16 @@ namespace MUtils
converter.FreeManaged(object); converter.FreeManaged(object);
} }
/// <summary>
/// Releases the managed resources of a boxed object.
/// </summary>
template<class T>
void FreeManagedArray(MArray* array)
{
MConverter<T> converter;
converter.FreeManagedArray(array);
}
/// <summary> /// <summary>
/// Links managed array data to the unmanaged BytesContainer. /// Links managed array data to the unmanaged BytesContainer.
/// </summary> /// </summary>
@@ -690,6 +863,52 @@ namespace MUtils
} }
#if USE_NETCORE #if USE_NETCORE
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
template<typename T>
FORCE_INLINE T* ToNativeArray(const Array<T>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
T* arr = (T*)MCore::GC::AllocateMemory(data.Count() * sizeof(T), true);
Platform::MemoryCopy(arr, data.Get(), data.Count() * sizeof(T));
return arr;
}
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
template<typename T, typename AllocationType = HeapAllocation>
FORCE_INLINE NativeArray<T> ToNativeArrayWrapper(const Array<T, AllocationType>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<T> arr;
arr.length = data.Count();
arr.data = (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true);
Platform::MemoryCopy(arr.data, data.Get(), arr.length * sizeof(T));
return arr;
}
/// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary>
/// <param name="data">The input data.</param>
/// <returns>The output array.</returns>
template<typename T>
FORCE_INLINE NativeArray<T> ToNativeArrayWrapper(const Span<T>& data)
{
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
NativeArray<T> arr;
arr.length = data.Length();
arr.data = (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true);
Platform::MemoryCopy(arr.data, data.Get(), arr.length * sizeof(T));
return arr;
}
/// <summary> /// <summary>
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data. /// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
/// </summary> /// </summary>

View File

@@ -400,9 +400,14 @@ MObject* MCore::Object::Box(void* value, const MClass* klass)
} }
void* MCore::Object::Unbox(MObject* obj) void* MCore::Object::Unbox(MObject* obj)
{
CRASH; // Should not be used anymore
}
void MCore::Object::Unbox(MObject* obj, void* dest)
{ {
static void* UnboxValuePtr = GetStaticMethodPointer(TEXT("UnboxValue")); static void* UnboxValuePtr = GetStaticMethodPointer(TEXT("UnboxValue"));
return CallStaticMethod<void*, void*>(UnboxValuePtr, obj); return CallStaticMethod<void, void*, void*>(UnboxValuePtr, obj, dest);
} }
MObject* MCore::Object::New(const MClass* klass) MObject* MCore::Object::New(const MClass* klass)
@@ -462,12 +467,24 @@ StringView MCore::String::GetChars(MString* obj)
return StringView(chars, length); return StringView(chars, length);
} }
void MCore::String::Free(MString* obj)
{
static void* FreeStringPtr = GetStaticMethodPointer(TEXT("FreeString"));
CallStaticMethod<void, void*>(FreeStringPtr, obj);
}
MArray* MCore::Array::New(const MClass* elementKlass, int32 length) MArray* MCore::Array::New(const MClass* elementKlass, int32 length)
{ {
static void* NewArrayPtr = GetStaticMethodPointer(TEXT("NewArray")); static void* NewArrayPtr = GetStaticMethodPointer(TEXT("NewArray"));
return (MArray*)CallStaticMethod<void*, void*, long long>(NewArrayPtr, elementKlass->_handle, length); return (MArray*)CallStaticMethod<void*, void*, long long>(NewArrayPtr, elementKlass->_handle, length);
} }
void MCore::Array::Free(const MArray* array)
{
static void* FreeArrayPtr = GetStaticMethodPointer(TEXT("FreeArray"));
CallStaticMethod<void, void*>(FreeArrayPtr, (void*)array);
}
MClass* MCore::Array::GetClass(MClass* elementKlass) MClass* MCore::Array::GetClass(MClass* elementKlass)
{ {
static void* GetArrayTypeFromElementTypePtr = GetStaticMethodPointer(TEXT("GetArrayTypeFromElementType")); static void* GetArrayTypeFromElementTypePtr = GetStaticMethodPointer(TEXT("GetArrayTypeFromElementType"));

View File

@@ -738,6 +738,11 @@ void* MCore::Object::Unbox(MObject* obj)
//return mono_object_unbox(obj); //return mono_object_unbox(obj);
} }
void MCore::Object::Unbox(MObject* obj, void* dest)
{
CRASH; // Not applicable
}
MObject* MCore::Object::New(const MClass* klass) MObject* MCore::Object::New(const MClass* klass)
{ {
return mono_object_new(mono_domain_get(), klass->GetNative()); return mono_object_new(mono_domain_get(), klass->GetNative());
@@ -787,12 +792,20 @@ StringView MCore::String::GetChars(MString* obj)
return StringView(mono_string_chars(obj), (int32)mono_string_length(obj)); return StringView(mono_string_chars(obj), (int32)mono_string_length(obj));
} }
void MCore::String::Free(MString* obj)
{
}
MArray* MCore::Array::New(const MClass* elementKlass, int32 length) MArray* MCore::Array::New(const MClass* elementKlass, int32 length)
{ {
// TODO: use shared empty arrays cache // TODO: use shared empty arrays cache
return mono_array_new(mono_domain_get(), elementKlass->GetNative(), length); return mono_array_new(mono_domain_get(), elementKlass->GetNative(), length);
} }
void MCore::Array::Free(const MArray* array)
{
}
MClass* MCore::Array::GetClass(MClass* elementKlass) MClass* MCore::Array::GetClass(MClass* elementKlass)
{ {
MonoClass* monoClass = mono_array_class_get(elementKlass->GetNative(), 1); MonoClass* monoClass = mono_array_class_get(elementKlass->GetNative(), 1);

View File

@@ -80,6 +80,10 @@ void* MCore::Object::Unbox(MObject* obj)
return nullptr; return nullptr;
} }
void MCore::Object::Unbox(MObject* obj, void* dest)
{
}
MObject* MCore::Object::New(const MClass* klass) MObject* MCore::Object::New(const MClass* klass)
{ {
return nullptr; return nullptr;
@@ -124,11 +128,19 @@ StringView MCore::String::GetChars(MString* obj)
return StringView::Empty; return StringView::Empty;
} }
void MCore::String::Free(MString* obj)
{
}
MArray* MCore::Array::New(const MClass* elementKlass, int32 length) MArray* MCore::Array::New(const MClass* elementKlass, int32 length)
{ {
return nullptr; return nullptr;
} }
void MCore::Array::Free(const MArray* array)
{
}
MClass* MCore::Array::GetClass(MClass* elementKlass) MClass* MCore::Array::GetClass(MClass* elementKlass)
{ {
return nullptr; return nullptr;

View File

@@ -633,8 +633,62 @@ namespace Flax.Build.Bindings
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.SystemArrayMarshaller))"; returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.SystemArrayMarshaller))";
else if (returnValueType == "object[]") else if (returnValueType == "object[]")
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.SystemObjectArrayMarshaller))"; returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.SystemObjectArrayMarshaller))";
else if (functionInfo.ReturnType.IsArrayOrSpan || returnNativeType == "Array")
{
string unmanagedType = "";
if (functionInfo.ReturnType.GenericArgs != null && functionInfo.ReturnType.GenericArgs[0].IsPod(buildData, caller))
{
switch (functionInfo.ReturnType.GenericArgs[0].Type)
{
case "bool": unmanagedType = "U1"; break;
case "byte": unmanagedType = "U1"; break;
case "sbyte": unmanagedType = "I1"; break;
case "char": unmanagedType = "I2"; break;
case "short": case "int16": unmanagedType = "I2"; break;
case "ushort": case "uint16": unmanagedType = "U2"; break;
case "int": case "int32": unmanagedType = "I4"; break;
case "uint": case "uint32": unmanagedType = "U4"; break;
case "long": case "int64": unmanagedType = "I8"; break;
case "ulong": case "uint64": unmanagedType = "U8"; break;
case "float": unmanagedType = "R4"; break;
case "double": unmanagedType = "R8"; break;
case "Float2":
case "Double2":
case "Vector2":
case "Float3":
case "Double3":
case "Vector3":
case "Float4":
case "Double4":
case "Vector4":
case "Color":
case "Color32":
case "Guid":
unmanagedType = "Any"; // FIXME
break;
default:
unmanagedType = "Any";
//Log.Warning($"unknown type: '{parameterInfo.Type.GenericArgs[0].Type}'");
break;
}
}
if (!string.IsNullOrEmpty(unmanagedType))
{
string arraySubType = "";
if (unmanagedType != "Any")
arraySubType = $"ArraySubType = UnmanagedType.{unmanagedType}, ";
returnMarshalType = $"MarshalAs(UnmanagedType.LPArray, {arraySubType}SizeParamIndex = {(!functionInfo.IsStatic ? 1 : 0) + functionInfo.Parameters.Count + (functionInfo.Glue.CustomParameters.FindIndex(x => x.Name == $"__returnCount"))})";
}
else
returnMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = \"__returnCount\")";
}
else if (functionInfo.ReturnType.Type == "Array" || functionInfo.ReturnType.Type == "Span" || functionInfo.ReturnType.Type == "DataContainer" || functionInfo.ReturnType.Type == "BytesContainer" || returnNativeType == "Array") else if (functionInfo.ReturnType.Type == "Array" || functionInfo.ReturnType.Type == "Span" || functionInfo.ReturnType.Type == "DataContainer" || functionInfo.ReturnType.Type == "BytesContainer" || returnNativeType == "Array")
{
//[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U1, SizeParamIndex = 8)]
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = nameof(__returnCount))"; returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = nameof(__returnCount))";
}
else if (functionInfo.ReturnType.Type == "Dictionary") else if (functionInfo.ReturnType.Type == "Dictionary")
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)"; returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)";
else if (returnValueType == "byte[]") else if (returnValueType == "byte[]")
@@ -686,11 +740,56 @@ namespace Flax.Build.Bindings
parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.SystemArrayMarshaller))"; parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.SystemArrayMarshaller))";
else if (nativeType == "object[]") else if (nativeType == "object[]")
parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.SystemObjectArrayMarshaller))"; parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.SystemObjectArrayMarshaller))";
else if (parameterInfo.Type.Type == "Array" && parameterInfo.Type.GenericArgs.Count > 0 && parameterInfo.Type.GenericArgs[0].Type == "bool") else if (parameterInfo.Type.IsArrayOrSpan || nativeType == "Array")
parameterMarshalType = $"MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U1, SizeParamIndex = {(!functionInfo.IsStatic ? 1 : 0) + functionInfo.Parameters.Count + (functionInfo.Glue.CustomParameters.FindIndex(x => x.Name == $"__{parameterInfo.Name}Count"))})";
else if (parameterInfo.Type.Type == "Array" || parameterInfo.Type.Type == "Span" || parameterInfo.Type.Type == "DataContainer" || parameterInfo.Type.Type == "BytesContainer" || nativeType == "Array")
{ {
parameterMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = \"__{parameterInfo.Name}Count\")"; string unmanagedType = "";
if (parameterInfo.Type.GenericArgs != null && parameterInfo.Type.GenericArgs[0].IsPod(buildData, caller))
{
switch (parameterInfo.Type.GenericArgs[0].Type)
{
case "bool": unmanagedType = "U1"; break;
case "byte": unmanagedType = "U1"; break;
case "sbyte": unmanagedType = "I1"; break;
case "char": unmanagedType = "I2"; break;
case "short": case "int16": unmanagedType = "I2"; break;
case "ushort": case "uint16": unmanagedType = "U2"; break;
case "int": case "int32": unmanagedType = "I4"; break;
case "uint": case "uint32": unmanagedType = "U4"; break;
case "long": case "int64": unmanagedType = "I8"; break;
case "ulong": case "uint64": unmanagedType = "U8"; break;
case "float": unmanagedType = "R4"; break;
case "double": unmanagedType = "R8"; break;
case "Float2":
case "Double2":
case "Vector2":
case "Float3":
case "Double3":
case "Vector3":
case "Float4":
case "Double4":
case "Vector4":
case "Color":
case "Color32":
case "Guid":
unmanagedType = "Any"; // FIXME
break;
default:
unmanagedType = "Any";
//Log.Warning($"unknown type: '{parameterInfo.Type.GenericArgs[0].Type}'");
break;
}
}
if (!string.IsNullOrEmpty(unmanagedType))
{
string arraySubType = "";
if (unmanagedType != "Any")
arraySubType = $"ArraySubType = UnmanagedType.{unmanagedType}, ";
parameterMarshalType = $"MarshalAs(UnmanagedType.LPArray, {arraySubType}SizeParamIndex = {(!functionInfo.IsStatic ? 1 : 0) + functionInfo.Parameters.Count + (functionInfo.Glue.CustomParameters.FindIndex(x => x.Name == $"__{parameterInfo.Name}Count"))})";
}
else
parameterMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = \"__{parameterInfo.Name}Count\")";
if (!parameterInfo.IsOut && !parameterInfo.IsRef) if (!parameterInfo.IsOut && !parameterInfo.IsRef)
parameterMarshalType += ", In"; // The usage of 'LibraryImportAttribute' does not follow recommendations. It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. parameterMarshalType += ", In"; // The usage of 'LibraryImportAttribute' does not follow recommendations. It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters.
} }
@@ -741,7 +840,7 @@ namespace Flax.Build.Bindings
if (parameterInfo.IsOut && parameterInfo.DefaultValue == "var __resultAsRef") if (parameterInfo.IsOut && parameterInfo.DefaultValue == "var __resultAsRef")
{ {
// TODO: make this code shared with MarshalUsing selection from the above // TODO: make this code shared with MarshalUsing selection from the above
if (parameterInfo.Type.Type == "Array" || parameterInfo.Type.Type == "Span" || parameterInfo.Type.Type == "DataContainer" || parameterInfo.Type.Type == "BytesContainer") if (parameterInfo.Type.IsArrayOrSpan)
parameterMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = \"{parameterInfo.Name}Count\")"; parameterMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = \"{parameterInfo.Name}Count\")";
else if (parameterInfo.Type.Type == "Dictionary") else if (parameterInfo.Type.Type == "Dictionary")
parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)"; parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)";

View File

@@ -388,17 +388,7 @@ namespace Flax.Build.Bindings
// Find namespace for this type to build a fullname // Find namespace for this type to build a fullname
if (apiType != null) if (apiType != null)
{ managedType = apiType.Namespace + '.' + managedType.Replace(".", "+");
var e = apiType.Parent;
while (!(e is FileInfo))
{
e = e.Parent;
}
if (e is FileInfo fileInfo && !managedType.StartsWith(fileInfo.Namespace))
{
managedType = fileInfo.Namespace + '.' + managedType.Replace(".", "+");
}
}
// Use runtime lookup from fullname of the C# class // Use runtime lookup from fullname of the C# class
return "Scripting::FindClass(\"" + managedType + "\")"; return "Scripting::FindClass(\"" + managedType + "\")";
@@ -541,14 +531,25 @@ namespace Flax.Build.Bindings
if ((typeInfo.Type == "Array" || typeInfo.Type == "Span" || typeInfo.Type == "DataContainer") && typeInfo.GenericArgs != null) if ((typeInfo.Type == "Array" || typeInfo.Type == "Span" || typeInfo.Type == "DataContainer") && typeInfo.GenericArgs != null)
{ {
var arrayTypeInfo = typeInfo.GenericArgs[0]; var arrayTypeInfo = typeInfo.GenericArgs[0];
#if USE_NETCORE
// Boolean arrays does not support custom marshalling for some unknown reason
if (arrayTypeInfo.Type == "bool")
{
type = "bool*";
return "MUtils::ToBoolArray({0})";
}
var arrayApiType = FindApiTypeInfo(buildData, arrayTypeInfo, caller); var arrayApiType = FindApiTypeInfo(buildData, arrayTypeInfo, caller);
#if USE_NETCORE
if (arrayApiType?.IsPod ?? false)
{
if (functionInfo == null)
{
// Storage type should be wrapped
type = $"NativeArray<{arrayApiType.FullNameNative}>";
return $"MUtils::ToNativeArrayWrapper<{arrayApiType.FullNameNative}>({{0}})/*sahho*/";
}
else
{
//type = arrayApiType.FullNameNative + "*/*wahho*/";
type = $"NativeArray<{arrayApiType.FullNameNative}>/*tahho*/";
//if (arrayTypeInfo.Type == "bool")
// return "MUtils::ToBoolArray({0})/*bahho*/";
return "MUtils::ToNativeArrayWrapper({0})/*nahhoa7eatra*/";
}
}
#endif #endif
type = "MArray*"; type = "MArray*";
if (arrayApiType != null && arrayApiType.MarshalAs != null) if (arrayApiType != null && arrayApiType.MarshalAs != null)
@@ -564,12 +565,14 @@ namespace Flax.Build.Bindings
return "MUtils::ToArray({0}, " + GenerateCppGetMClass(buildData, arrayTypeInfo, caller, functionInfo) + ")"; return "MUtils::ToArray({0}, " + GenerateCppGetMClass(buildData, arrayTypeInfo, caller, functionInfo) + ")";
} }
#if !USE_NETCORE
// Span // Span
if (typeInfo.Type == "Span" && typeInfo.GenericArgs != null) if (typeInfo.Type == "Span" && typeInfo.GenericArgs != null)
{ {
type = "MonoArray*"; type = "MonoArray*";
return "MUtils::Span({0}, " + GenerateCppGetMClass(buildData, typeInfo.GenericArgs[0], caller, functionInfo) + ")"; return "MUtils::Span({0}, " + GenerateCppGetMClass(buildData, typeInfo.GenericArgs[0], caller, functionInfo) + ")";
} }
#endif
// BytesContainer // BytesContainer
if (typeInfo.Type == "BytesContainer" && typeInfo.GenericArgs == null) if (typeInfo.Type == "BytesContainer" && typeInfo.GenericArgs == null)
@@ -600,7 +603,7 @@ namespace Flax.Build.Bindings
{ {
CppIncludeFiles.Add("Engine/Scripting/Internal/ManagedBitArray.h"); CppIncludeFiles.Add("Engine/Scripting/Internal/ManagedBitArray.h");
#if USE_NETCORE #if USE_NETCORE
// Boolean arrays does not support custom marshalling for some unknown reason // Special case for copying bits to bytes
type = "bool*"; type = "bool*";
return "MUtils::ToBoolArray({0})"; return "MUtils::ToBoolArray({0})";
#else #else
@@ -752,6 +755,7 @@ namespace Flax.Build.Bindings
// Array // Array
if (typeInfo.Type == "Array" && typeInfo.GenericArgs != null) if (typeInfo.Type == "Array" && typeInfo.GenericArgs != null)
{ {
needLocalVariable = true;
var arrayTypeInfo = typeInfo.GenericArgs[0]; var arrayTypeInfo = typeInfo.GenericArgs[0];
var arrayApiType = FindApiTypeInfo(buildData, arrayTypeInfo, caller); var arrayApiType = FindApiTypeInfo(buildData, arrayTypeInfo, caller);
if (arrayApiType != null && arrayApiType.MarshalAs != null) if (arrayApiType != null && arrayApiType.MarshalAs != null)
@@ -771,6 +775,16 @@ namespace Flax.Build.Bindings
genericArgs += ", " + typeInfo.GenericArgs[1]; genericArgs += ", " + typeInfo.GenericArgs[1];
result = $"Array<{genericArgs}>({result})"; result = $"Array<{genericArgs}>({result})";
} }
else if (arrayApiType?.IsPod ?? false)
{
type = arrayApiType.FullNameNative + '*';
result = $"Array<{genericArgs}>(({arrayApiType.FullNameNative}*){{0}}, {{1}})/*xviox1 {arrayTypeInfo.Type}*/";
}
else if (arrayApiType?.Name == "bool")
{
type = "bool*";
result = "Array<bool>({0}, {1})/*xviox2*/\"";
}
return result; return result;
} }
@@ -780,11 +794,20 @@ namespace Flax.Build.Bindings
type = "MArray*"; type = "MArray*";
// Scripting Objects pointers has to be converted from managed object pointer into native object pointer to use Array converted for this // Scripting Objects pointers has to be converted from managed object pointer into native object pointer to use Array converted for this
var t = FindApiTypeInfo(buildData, typeInfo.GenericArgs[0], caller); var arrayApiType = FindApiTypeInfo(buildData, typeInfo.GenericArgs[0], caller);
if (typeInfo.GenericArgs[0].IsPtr && t != null && t.IsScriptingObject) if (typeInfo.GenericArgs[0].IsPtr && arrayApiType != null && arrayApiType.IsScriptingObject)
{ {
// TODO: array needs to be freed
return "MUtils::ToSpan<" + typeInfo.GenericArgs[0] + ">(" + "MUtils::ToArray<" + typeInfo.GenericArgs[0] + ">({0}))"; return "MUtils::ToSpan<" + typeInfo.GenericArgs[0] + ">(" + "MUtils::ToArray<" + typeInfo.GenericArgs[0] + ">({0}))";
} }
else if (arrayApiType?.IsPod ?? false)
{
type = arrayApiType.FullNameNative + '*';
var nativeName = arrayApiType.FullNameNative;
if (typeInfo.GenericArgs[0].IsConst)
nativeName = "const " + nativeName;
return $"Span<{nativeName}>({{0}}, {{1}})/*spantag */";
}
return "MUtils::ToSpan<" + typeInfo.GenericArgs[0] + ">({0})"; return "MUtils::ToSpan<" + typeInfo.GenericArgs[0] + ">({0})";
} }
@@ -1251,8 +1274,16 @@ namespace Flax.Build.Bindings
callParams += ", "; callParams += ", ";
separator = true; separator = true;
var name = parameterInfo.Name; var name = parameterInfo.Name;
var countParamName = $"__{parameterInfo.Name}Count";
if (CppParamsThatNeedConversion[i] && (!FindApiTypeInfo(buildData, parameterInfo.Type, caller)?.IsStruct ?? false)) if (CppParamsThatNeedConversion[i] && (!FindApiTypeInfo(buildData, parameterInfo.Type, caller)?.IsStruct ?? false))
{
name = '*' + name; name = '*' + name;
countParamName = '*' + countParamName + "/*plop*/";
}
else if (parameterInfo.Type.IsRef)
{
countParamName = '*' + countParamName + "/*plipa*/";
}
string param = string.Empty; string param = string.Empty;
if (string.IsNullOrWhiteSpace(CppParamsWrappersCache[i])) if (string.IsNullOrWhiteSpace(CppParamsWrappersCache[i]))
@@ -1265,7 +1296,7 @@ namespace Flax.Build.Bindings
else else
{ {
// Convert value // Convert value
param += string.Format(CppParamsWrappersCache[i], name); param += string.Format(CppParamsWrappersCache[i], name, countParamName);
} }
// Special case for output result parameters that needs additional converting from native to managed format (such as non-POD structures or output array parameter) // Special case for output result parameters that needs additional converting from native to managed format (such as non-POD structures or output array parameter)
@@ -1349,6 +1380,25 @@ namespace Flax.Build.Bindings
contents.Append(';'); contents.Append(';');
contents.AppendLine(); contents.AppendLine();
#if false
for (var i = 0; i < functionInfo.Parameters.Count; i++)
{
var parameterInfo = functionInfo.Parameters[i];
if (CppParamsThatNeedConversion[i] || CppParamsThatNeedLocalVariable[i])
{
var apiType = FindApiTypeInfo(buildData, parameterInfo.Type, caller);
if (parameterInfo.Type.Type == "Array")
{
contents.Append(indent).AppendLine($"/* converthing: {parameterInfo.Name} Type == {parameterInfo.Type.Type} ({parameterInfo.Type.ToString()}) */");
contents.Append(indent).AppendLine($"/* converthing2: {parameterInfo.Name} IsArray == {parameterInfo.Type.IsArray} */");
contents.Append(indent).AppendLine($"/* converthing3: {parameterInfo.Name} apitype == {apiType?.Name ?? ""} */");
//contents.Append(indent).AppendLine($"MUtils::FreeManagedArray<{parameterInfo.Type.GenericArgs[0].ToString(false)}>({parameterInfo.Name}Temp);");
}
}
}
#endif
// Convert special parameters back to managed world // Convert special parameters back to managed world
if (!useInlinedReturn) if (!useInlinedReturn)
{ {
@@ -1360,6 +1410,7 @@ namespace Flax.Build.Bindings
if (CppParamsThatNeedConversion[i]) if (CppParamsThatNeedConversion[i])
{ {
var value = string.Format(CppParamsThatNeedConversionWrappers[i], parameterInfo.Name + "Temp"); var value = string.Format(CppParamsThatNeedConversionWrappers[i], parameterInfo.Name + "Temp");
var elementType = parameterInfo.Type.GenericArgs != null ? FindApiTypeInfo(buildData, parameterInfo.Type.GenericArgs[0], caller) : null;
// MObject* parameters returned by reference need write barrier for GC // MObject* parameters returned by reference need write barrier for GC
if (parameterInfo.IsOut) if (parameterInfo.IsOut)
@@ -1369,14 +1420,30 @@ namespace Flax.Build.Bindings
{ {
if (apiType.IsClass) if (apiType.IsClass)
{ {
contents.Append(indent).AppendFormat("MCore::GC::WriteRef({0}, (MObject*){1});", parameterInfo.Name, value).AppendLine();
#if USE_NETCORE #if USE_NETCORE
if (parameterInfo.Type.Type == "Array") if (parameterInfo.Type.Type == "Array")
{ {
if (elementType?.IsPod ?? false)
{
contents.Append(indent).Append($"// isgigs1a").AppendLine();
contents.Append(indent).Append($"*{parameterInfo.Name} = ({parameterInfo.Type.GenericArgs[0]}*)MCore::GC::AllocateMemory(sizeof({parameterInfo.Type.GenericArgs[0]}) * {parameterInfo.Name}Temp.Count());").AppendLine();
contents.Append(indent).Append($"Platform::MemoryCopy(*{parameterInfo.Name}, {parameterInfo.Name}Temp.Get(), sizeof({parameterInfo.Type.GenericArgs[0]}) * {parameterInfo.Name}Temp.Count());").AppendLine();
}
else
{
contents.Append(indent).Append($"// isgigs1b").AppendLine();
contents.Append(indent).AppendFormat("MCore::GC::WriteRef({0}, (MObject*){1});", parameterInfo.Name, value).AppendLine();
}
// Array marshallers need to know amount of items written in the buffer // Array marshallers need to know amount of items written in the buffer
contents.Append(indent).AppendFormat("*__{0}Count = {1}.Count();", parameterInfo.Name, parameterInfo.Name + "Temp").AppendLine(); contents.Append(indent).AppendFormat("*__{0}Count = {1}.Count();", parameterInfo.Name, parameterInfo.Name + "Temp").AppendLine();
} }
else
#endif #endif
{
contents.Append(indent).Append($"// isgigs2").AppendLine();
contents.Append(indent).AppendFormat("MCore::GC::WriteRef({0}, (MObject*){1});", parameterInfo.Name, value).AppendLine();
}
continue; continue;
} }
if (apiType.IsStruct && !apiType.IsPod) if (apiType.IsStruct && !apiType.IsPod)
@@ -1392,22 +1459,30 @@ namespace Flax.Build.Bindings
// BytesContainer // BytesContainer
if (parameterInfo.Type.Type == "BytesContainer" && parameterInfo.Type.GenericArgs == null) if (parameterInfo.Type.Type == "BytesContainer" && parameterInfo.Type.GenericArgs == null)
{ {
contents.Append(indent).Append($"// hshsf").AppendLine();
contents.Append(indent).AppendFormat("MCore::GC::WriteRef({0}, (MObject*){1});", parameterInfo.Name, value).AppendLine(); contents.Append(indent).AppendFormat("MCore::GC::WriteRef({0}, (MObject*){1});", parameterInfo.Name, value).AppendLine();
// Array marshallers need to know amount of items written in the buffer // Array marshallers need to know amount of items written in the buffer
contents.Append(indent).AppendFormat("*__{0}Count = {1}.Length();", parameterInfo.Name, parameterInfo.Name + "Temp").AppendLine(); //contents.Append(indent).AppendFormat("*__{0}Count = {1}.Length();", parameterInfo.Name, parameterInfo.Name + "Temp").AppendLine();
continue; //continue;
} }
else
throw new Exception($"Unsupported type of parameter '{parameterInfo}' in method '{functionInfo}' to be passed using 'out'"); throw new Exception($"Unsupported type of parameter '{parameterInfo}' in method '{functionInfo}' to be passed using 'out'");
} }
} }
contents.Append(indent).AppendFormat("*{0} = {1};", parameterInfo.Name, value).AppendLine(); else if (parameterInfo.Type.Type == "Array" && (elementType?.IsPod ?? false))
contents.Append(indent).AppendFormat("*{0} = {1}.data;", parameterInfo.Name, value).AppendLine();
else
contents.Append(indent).AppendFormat("*{0} = {1};", parameterInfo.Name, value).AppendLine();
#if USE_NETCORE #if USE_NETCORE
if (parameterInfo.Type.Type == "Array") if (parameterInfo.Type.Type == "Array" || (parameterInfo.Type.Type == "BytesContainer" && parameterInfo.Type.GenericArgs == null))
{ {
contents.Append(indent).Append("// hshshj").AppendLine();
// Array marshallers need to know amount of items written in the buffer // Array marshallers need to know amount of items written in the buffer
contents.Append(indent).AppendFormat("*__{0}Count = {1}.Count();", parameterInfo.Name, parameterInfo.Name + "Temp").AppendLine(); if (parameterInfo.Type.Type is "Span" or "BytesContainer")
contents.Append(indent).AppendFormat("*__{0}Count = {1}.Length();", parameterInfo.Name, parameterInfo.Name + "Temp").AppendLine();
else
contents.Append(indent).AppendFormat("*__{0}Count = {1}.Count();", parameterInfo.Name, parameterInfo.Name + "Temp").AppendLine();
} }
#endif #endif
} }
@@ -1722,6 +1797,52 @@ namespace Flax.Build.Bindings
contents.Append($" MCore::GCHandle::Free(__param{i}_handle);").AppendLine(); contents.Append($" MCore::GCHandle::Free(__param{i}_handle);").AppendLine();
} }
} }
else if (paramValue.Contains("MUtils::ToArray(")) // FIXME
{
var genericType = parameterInfo.Type.GenericArgs[0].ToString(false);
if (paramIsRef)
{
//contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.ToString(false)}>((MObject*)__param_{parameterInfo.Name});").AppendLine();
/*if (useThunk)
{
// Release the original handle
contents.Append($" if (__param_orig_{parameterInfo.Name} != __param_{parameterInfo.Name}) //asdf1a").AppendLine();
contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.ToString(false)}>((MObject*)__param_{parameterInfo.Name});").AppendLine();
}*/
contents.Append($" MUtils::FreeManagedArray<{genericType}>(__param_{parameterInfo.Name}); //fgfgh3").AppendLine();
if (useThunk)
{
// Release the original handle
contents.Append($" if (__param_orig_{parameterInfo.Name} != __param_{ parameterInfo.Name})").AppendLine();
contents.Append($" MUtils::FreeManagedArray<{genericType}>(__param_orig_{parameterInfo.Name}); //fgfgh4").AppendLine();
}
}
else if (apiType != null && !apiType.IsInBuild)
{
// int: ispod, isvaluetype
// vector: ispod, isvaluetype, isstruct
// guid: ispod, isvaluetype, isstruct, isinbuild
contents.Append($" MUtils::FreeManagedArray<{genericType}>((MArray*)params[{i}]); //fgfgh5").AppendLine();
//contents.Append($" auto __param{i}_handle = *(MGCHandle*)&params[{i}]; // asdf1b").AppendLine();
//contents.Append($" ASSERT((((unsigned long long)__param{i}_handle & 0xC000000000000000) >> 62) == 0);").AppendLine();
//contents.Append($" MCore::GCHandle::Free(__param{i}_handle);").AppendLine();
}
else if (apiType != null && !apiType.IsValueType)
{
if (parameterInfo.Type.Type.ToLower().Contains("string"))
apiType = apiType;
contents.Append($" MUtils::FreeManagedArray<{genericType}>((MArray*)params[{i}]); //fgfgh6").AppendLine();
}
else //if (apiType != null)
{
if (parameterInfo.Type.Type.ToLower().Contains("string"))
apiType = apiType;
//contents.Append($" //asdf1c {parameterInfo.Type.Type}").AppendLine();
contents.Append($" auto __param{i}_handle = *(MGCHandle*)&params[{i}]; //fgfgh7").AppendLine();
//contents.Append($" ASSERT((((unsigned long long)__param{i}_handle & 0xC000000000000000) >> 62) == 0);").AppendLine();
contents.Append($" MCore::GCHandle::Free(__param{i}_handle);").AppendLine();
}
}
} }
contents.AppendLine(" WrapperCallInstance = prevWrapperCallInstance;"); contents.AppendLine(" WrapperCallInstance = prevWrapperCallInstance;");
@@ -2568,14 +2689,20 @@ namespace Flax.Build.Bindings
contents.AppendLine(" }").AppendLine(); contents.AppendLine(" }").AppendLine();
// Unboxing structures from managed object to native data // Unboxing structures from managed object to native data
contents.AppendLine(" static void Unbox(void* ptr, MObject* managed)"); contents.AppendLine(" static void Unbox(void* ptr, MObject* data)");
contents.AppendLine(" {"); contents.AppendLine(" {");
if (structureInfo.MarshalAs != null) if (structureInfo.MarshalAs != null)
contents.AppendLine($" MISSING_CODE(\"Boxing native type {structureInfo.Name} as {structureInfo.MarshalAs}\");"); // TODO: impl this contents.AppendLine($" MISSING_CODE(\"Boxing native type {structureInfo.Name} as {structureInfo.MarshalAs}\");"); // TODO: impl this
else if (structureInfo.IsPod) else if (structureInfo.IsPod)
contents.AppendLine($" Platform::MemoryCopy(ptr, MCore::Object::Unbox(managed), sizeof({structureTypeNameNative}));"); contents.AppendLine($" MCore::Object::Unbox(data, ptr);");
//contents.AppendLine($" Platform::MemoryCopy(ptr, MCore::Object::Unbox(data), sizeof({structureTypeNameNative}));");
else else
contents.AppendLine($" *({structureTypeNameNative}*)ptr = ToNative(*({GenerateCppManagedWrapperName(structureInfo)}*)MCore::Object::Unbox(managed));"); {
contents.AppendLine($" {GenerateCppManagedWrapperName(structureInfo)} managed;");
contents.AppendLine($" MCore::Object::Unbox(data, &managed);");
contents.AppendLine($" *({structureTypeNameNative}*)ptr = ToNative(managed);");
}
//contents.AppendLine($" *({structureTypeNameNative}*)ptr = ToNative(*({GenerateCppManagedWrapperName(structureInfo)}*)MCore::Object::Unbox(data));");
contents.AppendLine(" }").AppendLine(); contents.AppendLine(" }").AppendLine();
} }
else else
@@ -3109,15 +3236,18 @@ namespace Flax.Build.Bindings
header.AppendFormat(" DLLEXPORT USED MObject* Box(const {0}& data, const MClass* klass)", fullName).AppendLine(); header.AppendFormat(" DLLEXPORT USED MObject* Box(const {0}& data, const MClass* klass)", fullName).AppendLine();
header.Append(" {").AppendLine(); header.Append(" {").AppendLine();
header.Append(" auto managed = ToManaged(data);").AppendLine(); header.Append(" auto managed = ToManaged(data);").AppendLine();
header.Append(" return MCore::Object::Box((void*)&managed, klass);").AppendLine(); header.Append(" auto boxed = MCore::Object::Box((void*)&managed, klass);").AppendLine();
header.Append(" ::FreeManaged(managed);").AppendLine();
header.Append(" return boxed;").AppendLine();
header.Append(" }").AppendLine(); header.Append(" }").AppendLine();
header.AppendFormat(" DLLEXPORT USED void Unbox({0}& result, MObject* data)", fullName).AppendLine(); header.AppendFormat(" DLLEXPORT USED void Unbox({0}& result, MObject* data)", fullName).AppendLine();
header.Append(" {").AppendLine(); header.Append(" {").AppendLine();
//header.AppendFormat(" result = ToNative(*reinterpret_cast<{0}*>(MCore::Object::Unbox(data)));", wrapperName).AppendLine(); //header.AppendFormat(" result = ToNative(*reinterpret_cast<{0}*>(MCore::Object::Unbox(data)));", wrapperName).AppendLine();
header.AppendFormat(" auto managed = *reinterpret_cast<{0}*>(MCore::Object::Unbox(data));", wrapperName).AppendLine(); header.AppendFormat(" {0} managed;", wrapperName).AppendLine();
header.AppendFormat(" result = ToNative(managed);", wrapperName).AppendLine(); header.Append(" MCore::Object::Unbox(data, &managed);").AppendLine();
header.AppendFormat(" ::FreeManaged(managed);", wrapperName).AppendLine(); header.Append(" result = ToNative(managed);").AppendLine();
header.Append(" ::FreeManaged(managed);").AppendLine();
header.Append(" }").AppendLine(); header.Append(" }").AppendLine();
header.AppendFormat(" DLLEXPORT USED void ToManagedArray(MArray* result, const Span<{0}>& data)", fullName).AppendLine(); header.AppendFormat(" DLLEXPORT USED void ToManagedArray(MArray* result, const Span<{0}>& data)", fullName).AppendLine();
@@ -3126,8 +3256,8 @@ namespace Flax.Build.Bindings
header.AppendFormat(" {0}* resultPtr = ({0}*)MCore::Array::GetAddress(result);", wrapperName).AppendLine(); header.AppendFormat(" {0}* resultPtr = ({0}*)MCore::Array::GetAddress(result);", wrapperName).AppendLine();
header.Append(" for (int32 i = 0; i < data.Length(); i++)").AppendLine(); header.Append(" for (int32 i = 0; i < data.Length(); i++)").AppendLine();
header.Append(" {").AppendLine(); header.Append(" {").AppendLine();
header.Append(" auto managed = ToManaged(data[i]);").AppendLine(); header.Append(" auto managed = ToManaged(data[i]);").AppendLine();
header.Append(" MCore::GC::WriteValue(&resultPtr[i], &managed, 1, klass);").AppendLine(); header.Append(" MCore::GC::WriteValue(&resultPtr[i], &managed, 1, klass);").AppendLine();
header.Append(" }").AppendLine(); header.Append(" }").AppendLine();
header.Append(" }").AppendLine(); header.Append(" }").AppendLine();
@@ -3135,14 +3265,32 @@ namespace Flax.Build.Bindings
header.Append(" {").AppendLine(); header.Append(" {").AppendLine();
header.AppendFormat(" {0}* dataPtr = ({0}*)MCore::Array::GetAddress(data);", wrapperName).AppendLine(); header.AppendFormat(" {0}* dataPtr = ({0}*)MCore::Array::GetAddress(data);", wrapperName).AppendLine();
header.Append(" for (int32 i = 0; i < result.Length(); i++)").AppendLine(); header.Append(" for (int32 i = 0; i < result.Length(); i++)").AppendLine();
header.Append(" result[i] = ToNative(dataPtr[i]);").AppendLine(); header.Append(" result[i] = ToNative(dataPtr[i]);").AppendLine();
header.Append(" }").AppendLine(); header.Append(" }").AppendLine();
header.AppendFormat(" DLLEXPORT USED void FreeManaged(MObject* data)", fullName).AppendLine(); header.AppendFormat(" DLLEXPORT USED void FreeManaged(MObject* data)").AppendLine();
header.Append(" {").AppendLine(); header.Append(" {").AppendLine();
if (false) // FIXME: unboxing allocates temporary handles which FreeManaged does not free...
{
header.AppendFormat(" auto managed = reinterpret_cast<{0}*>(MCore::Object::Unbox(data));", wrapperName).AppendLine();
header.Append(" ::FreeManaged(*managed);").AppendLine();
}
header.Append(" MCore::GCHandle::Free(*(MGCHandle*)&data);").AppendLine();
header.Append(" }").AppendLine();
header.AppendFormat(" DLLEXPORT USED void FreeManagedArray(MArray* array)").AppendLine();
header.Append(" {").AppendLine();
header.AppendFormat(" {0}* resultPtr = ({0}*)MCore::Array::GetAddress(array);", wrapperName).AppendLine();
header.Append(" const auto length = MCore::Array::GetLength(array);").AppendLine();
header.Append(" for (int32 i = 0; i < length; ++i)").AppendLine();
header.Append(" {").AppendLine();
header.AppendFormat(" ::FreeManaged(*reinterpret_cast<{0}*>(&resultPtr[i]));", wrapperName).AppendLine();
header.Append(" }").AppendLine();
//header.Append(" PLATFORM_DEBUG_BREAK; // FIXME 1").AppendLine();
//header.AppendFormat(" auto managed = MCore::Object::Unbox(data);", wrapperName).AppendLine(); //header.AppendFormat(" auto managed = MCore::Object::Unbox(data);", wrapperName).AppendLine();
//header.AppendFormat(" ::FreeManaged(*reinterpret_cast<{0}*>(managed));", wrapperName).AppendLine(); //header.AppendFormat(" ::FreeManaged(*reinterpret_cast<{0}*>(managed));", wrapperName).AppendLine();
header.AppendFormat(" MCore::GCHandle::Free(*(MGCHandle*)&data);", wrapperName).AppendLine(); header.Append(" MCore::Array::Free(array);").AppendLine();
header.Append(" MCore::GCHandle::Free(*(MGCHandle*)&array);").AppendLine();
header.Append(" }").AppendLine(); header.Append(" }").AppendLine();
header.Append('}').Append(';').AppendLine(); header.Append('}').Append(';').AppendLine();
@@ -3192,9 +3340,11 @@ namespace Flax.Build.Bindings
continue; continue;
CppNonPodTypesConvertingGeneration = true; CppNonPodTypesConvertingGeneration = true;
var wrapper = GenerateCppWrapperManagedToNative(buildData, fieldInfo.Type, apiType, out _, out _, null, out _); var wrapper = GenerateCppWrapperManagedToNative(buildData, fieldInfo.Type, apiType, out var fieldTypeName, out var fieldType, null, out _);
CppNonPodTypesConvertingGeneration = false; CppNonPodTypesConvertingGeneration = false;
var arrayCountName = $"value.{fieldInfo.Name}.length";
if (fieldInfo.Type.IsArray) if (fieldInfo.Type.IsArray)
{ {
// Fixed-size array needs to unbox every item manually // Fixed-size array needs to unbox every item manually
@@ -3207,7 +3357,7 @@ namespace Flax.Build.Bindings
} }
else else
{ {
wrapper = string.Format(wrapper.Remove(wrapper.Length - 6), string.Format("value.{0}", fieldInfo.Name)); wrapper = string.Format(wrapper.Remove(wrapper.Length - 6), string.Format("value.{0}", fieldInfo.Name), arrayCountName);
header.AppendFormat(" auto tmp{0} = {1};", fieldInfo.Name, wrapper).AppendLine(); header.AppendFormat(" auto tmp{0} = {1};", fieldInfo.Name, wrapper).AppendLine();
header.AppendFormat(" for (int32 i = 0; i < {0} && i < tmp{1}.Count(); i++)", fieldInfo.Type.ArraySize, fieldInfo.Name).AppendLine(); header.AppendFormat(" for (int32 i = 0; i < {0} && i < tmp{1}.Count(); i++)", fieldInfo.Type.ArraySize, fieldInfo.Name).AppendLine();
header.AppendFormat(" result.{0}[i] = tmp{0}[i];", fieldInfo.Name).AppendLine(); header.AppendFormat(" result.{0}[i] = tmp{0}[i];", fieldInfo.Name).AppendLine();
@@ -3218,7 +3368,22 @@ namespace Flax.Build.Bindings
if (string.IsNullOrEmpty(wrapper)) if (string.IsNullOrEmpty(wrapper))
header.AppendFormat(" result.{0} = value.{0};", fieldInfo.Name).AppendLine(); header.AppendFormat(" result.{0} = value.{0};", fieldInfo.Name).AppendLine();
else else
header.AppendFormat(" result.{0} = {1};", fieldInfo.Name, string.Format(wrapper, string.Format("value.{0}", fieldInfo.Name))).AppendLine(); {
var arrayElementType = fieldInfo.Type.GenericArgs != null ? FindApiTypeInfo(buildData, fieldInfo.Type.GenericArgs[0], apiType) : null;
var ispod = (arrayElementType?.IsPod.ToString() ?? "null");
header.Append($" // {fieldInfo.Type.Type}, {fieldType?.FullNameNative}, {fieldType?.Name}, {fieldTypeName}, {ispod}").AppendLine();
if (fieldInfo.Type.IsArrayOrSpan && (arrayElementType?.IsPod ?? false))
{
header.AppendFormat(" result.{0} = {1}; /*kaek1 */", fieldInfo.Name, string.Format(wrapper, $"value.{fieldInfo.Name}.data", $"value.{fieldInfo.Name}.length")).AppendLine();
}
else
{
header.AppendFormat(" result.{0} = {1}; /*kaek2 */", fieldInfo.Name, string.Format(wrapper, $"value.{fieldInfo.Name}", $"value.{fieldInfo.Name}.lengthnot")).AppendLine();
}
//var fieldType = FindApiTypeInfo(buildData, fieldInfo.Type, apiType);
//header.AppendFormat(" result.{0} = {1}; /*kaek2*/", fieldInfo.Name, string.Format(wrapper, $"value.{fieldInfo.Name}")).AppendLine();
}
/*if (wrapper.Contains("::ToNative(")) // FIXME /*if (wrapper.Contains("::ToNative(")) // FIXME
{ {
header.Append($" auto __param{fieldInfo.Name}_handle = *(MGCHandle*)&value.{fieldInfo.Name};").AppendLine(); header.Append($" auto __param{fieldInfo.Name}_handle = *(MGCHandle*)&value.{fieldInfo.Name};").AppendLine();
@@ -3243,15 +3408,85 @@ namespace Flax.Build.Bindings
var wrapper = GenerateCppWrapperManagedToNative(buildData, fieldInfo.Type, apiType, out var managedType, out var fieldApiType, null, out _); var wrapper = GenerateCppWrapperManagedToNative(buildData, fieldInfo.Type, apiType, out var managedType, out var fieldApiType, null, out _);
CppNonPodTypesConvertingGeneration = false; CppNonPodTypesConvertingGeneration = false;
if (wrapper.Contains("::ToNative(")) // FIXME fieldApiType.IsScriptingObject if (fieldInfo.Type.IsArray)
{ {
//header.Append($" fixed_array_type = fixed_array_type; // {fieldInfo.Name} ({managedType}) is fixed array").AppendLine();
}
else if (string.IsNullOrEmpty(wrapper))
{
if (managedType == "bool")
{
}
else
{
}
}
else if (fieldInfo.Type.Type == "String" || managedType == "MString*")
{
if (fieldInfo.Type.Type != "String")
{
}
if (managedType != "MString*")
{
}
header.Append($" MCore::String::Free(value.{fieldInfo.Name});").AppendLine();
}
else if (fieldInfo.Type.Type == "Span")
{
}
else if (fieldInfo.Type.Type == "Array")
{
if (managedType == "MArray*")
{
}
else if (managedType == "Char*" || managedType == "char*")
{
}
else
{
//header.Append($" unhandled_type = unhandled_type; // {fieldInfo.Name} ({managedType}) should be cleaned? // asdfggg56").AppendLine();
}
}
else if (fieldApiType == null)
{
header.Append($" weird_type = weird_type; // {fieldInfo.Name} ({managedType}) is a weird one // okdfiodftg").AppendLine();
}
else if (fieldApiType.IsScriptingObject)
{
header.Append($" // {fieldInfo.Name} is a permanent handle // asdf2").AppendLine();
}
else if (!fieldApiType.IsPod) // FIXMEb
{
if (fieldApiType.IsClass)
{
}
else
{
header.Append($" ::FreeManaged(value.{fieldInfo.Name}); // asdfggg588").AppendLine();
//header.Append($" unhandled_type = unhandled_type; // {fieldInfo.Name} ({managedType}) should be cleaned? // asdfggg588").AppendLine();
}
header.Append($" auto __param{fieldInfo.Name}_handle = *(MGCHandle*)&value.{fieldInfo.Name};").AppendLine(); header.Append($" auto __param{fieldInfo.Name}_handle = *(MGCHandle*)&value.{fieldInfo.Name};").AppendLine();
//header.Append($" ASSERT((((unsigned long long)__param{fieldInfo.Name}_handle & 0xC000000000000000) >> 62) == 0); // asdf3").AppendLine(); //header.Append($" ASSERT((((unsigned long long)__param{fieldInfo.Name}_handle & 0xC000000000000000) >> 62) == 0); // asdf3").AppendLine();
header.Append($" if ((((unsigned long long)__param{fieldInfo.Name}_handle & 0xC000000000000000) >> 62) != 0) // asdf3").AppendLine(); header.Append($" if ((((unsigned long long)__param{fieldInfo.Name}_handle & 0xC000000000000000) >> 62) != 0) // asdf3").AppendLine();
header.Append($" __param{fieldInfo.Name}_handle = __param{fieldInfo.Name}_handle;").AppendLine(); header.Append($" __param{fieldInfo.Name}_handle = __param{fieldInfo.Name}_handle;").AppendLine();
header.Append($" MCore::GCHandle::Free(__param{fieldInfo.Name}_handle);").AppendLine(); header.Append($" MCore::GCHandle::Free(__param{fieldInfo.Name}_handle);").AppendLine();
} }
else if (fieldApiType.IsPod)
{
}
else
{
}
} }
if (classInfo != null) if (classInfo != null)
{ {
@@ -3338,9 +3573,27 @@ namespace Flax.Build.Bindings
header.AppendFormat(" Unbox(result[i], dataPtr[i]);", fullName).AppendLine(); header.AppendFormat(" Unbox(result[i], dataPtr[i]);", fullName).AppendLine();
header.Append(" }").AppendLine(); header.Append(" }").AppendLine();
header.AppendFormat(" DLLEXPORT USED void FreeManaged(MObject* data) // honk1", fullName).AppendLine(); header.AppendFormat(" DLLEXPORT USED void FreeManaged(MObject* data)").AppendLine();
header.Append(" {").AppendLine(); header.Append(" {").AppendLine();
//header.Append(" ::FreeManaged(reinterpret_cast<OnlineUserManaged*>(MCore::Object::Unbox(data)));").AppendLine(); header.Append(" PLATFORM_DEBUG_BREAK; // FIXME 2b").AppendLine();
header.Append(" MCore::GCHandle::Free(*(MGCHandle*)&data);").AppendLine();
header.Append(" }").AppendLine();
header.AppendFormat(" DLLEXPORT USED void FreeManagedArray(MArray* array)").AppendLine();
header.Append(" {").AppendLine();
header.Append(" PLATFORM_DEBUG_BREAK; // FIXME 2").AppendLine();
header.Append(" MObject** resultPtr = (MObject**)MCore::Array::GetAddress(array);").AppendLine();
header.Append(" const auto length = MCore::Array::GetLength(array);").AppendLine();
header.Append(" for (int32 i = 0; i < length; ++i)").AppendLine();
header.Append(" {").AppendLine();
header.Append(" FreeManaged(resultPtr[i]);").AppendLine();
//header.AppendFormat(" MCore::GCHandle::Free(*(MGCHandle*)&resultPtr[i]);", wrapperName).AppendLine();
header.Append(" }").AppendLine();
//header.Append(" PLATFORM_DEBUG_BREAK; // FIXME 1").AppendLine();
//header.AppendFormat(" auto managed = MCore::Object::Unbox(data);", wrapperName).AppendLine();
//header.AppendFormat(" ::FreeManaged(*reinterpret_cast<{0}*>(managed));", wrapperName).AppendLine();
header.Append(" MCore::Array::Free(array);").AppendLine();
header.Append(" MCore::GCHandle::Free(*(MGCHandle*)&array);").AppendLine();
header.Append(" }").AppendLine(); header.Append(" }").AppendLine();
header.Append('}').Append(';').AppendLine(); header.Append('}').Append(';').AppendLine();

View File

@@ -18,30 +18,42 @@ namespace Flax.Build.Bindings
public bool IsRef; public bool IsRef;
public bool IsMoveRef; public bool IsMoveRef;
public bool IsPtr; public bool IsPtr;
/// <summary>
/// Is this a fixed-length type of array.
/// </summary>
public bool IsArray; public bool IsArray;
public bool IsBitField; public bool IsBitField;
public int ArraySize; public int ArraySize;
public int BitSize; public int BitSize;
public List<TypeInfo> GenericArgs; public List<TypeInfo> GenericArgs;
/// <summary> /// <summary>
/// Gets a value indicating whether this type is void. /// Is this a void type.
/// </summary> /// </summary>
public bool IsVoid => Type == "void" && !IsPtr; public bool IsVoid => Type == "void" && !IsPtr;
/// <summary> /// <summary>
/// Gets a value indicating whether this type is constant reference to a value. /// Is this a constant reference to a value.
/// </summary> /// </summary>
public bool IsConstRef => IsRef && IsConst; public bool IsConstRef => IsRef && IsConst;
/// <summary> /// <summary>
/// Gets a value indicating whether this type is a reference to another object. /// Is this a reference to another FlaxEngine.Object.
/// </summary> /// </summary>
public bool IsObjectRef => (Type == "ScriptingObjectReference" || public bool IsObjectRef => Type is "ScriptingObjectReference"
Type == "AssetReference" || or "AssetReference"
Type == "WeakAssetReference" || or "WeakAssetReference"
Type == "SoftAssetReference" || or "SoftAssetReference"
Type == "SoftObjectReference") && GenericArgs != null; or "SoftObjectReference"
&& GenericArgs != null;
/// <summary>
/// Is this an inbuilt container type.
/// </summary>
public bool IsArrayOrSpan => Type is "Array" or "Span" or "DataContainer" or "BytesContainer";
public TypeInfo() public TypeInfo()
{ {