Add MarshalAs tag to APi structs/classes for custom marshaling via implicit casting

This commit is contained in:
Wojtek Figat
2023-08-19 16:59:39 +02:00
parent 32c47949fa
commit e36bf6e19a
6 changed files with 39 additions and 9 deletions

View File

@@ -22,6 +22,7 @@ namespace Flax.Build.Bindings
public string[] Comment;
public bool IsInBuild;
public bool IsDeprecated;
public string MarshalAs;
internal bool IsInited;
internal TypedefInfo Instigator;
@@ -151,6 +152,7 @@ namespace Flax.Build.Bindings
BindingsGenerator.Write(writer, Namespace);
BindingsGenerator.Write(writer, Attributes);
BindingsGenerator.Write(writer, Comment);
BindingsGenerator.Write(writer, MarshalAs);
writer.Write(IsInBuild);
writer.Write(IsDeprecated);
BindingsGenerator.Write(writer, Tags);
@@ -164,6 +166,7 @@ namespace Flax.Build.Bindings
Namespace = BindingsGenerator.Read(reader, Namespace);
Attributes = BindingsGenerator.Read(reader, Attributes);
Comment = BindingsGenerator.Read(reader, Comment);
MarshalAs = BindingsGenerator.Read(reader, MarshalAs);
IsInBuild = reader.ReadBoolean();
IsDeprecated = reader.ReadBoolean();
Tags = BindingsGenerator.Read(reader, Tags);

View File

@@ -196,6 +196,9 @@ namespace Flax.Build.Bindings
var apiType = FindApiTypeInfo(buildData, typeInfo, caller);
if (apiType != null)
{
if (apiType.MarshalAs != null)
return UsePassByReference(buildData, new TypeInfo(apiType.MarshalAs), caller);
// Skip for scripting objects
if (apiType.IsScriptingObject)
return false;

View File

@@ -420,6 +420,8 @@ namespace Flax.Build.Bindings
apiTypeParent = apiTypeParent.Parent;
}
if (apiType.MarshalAs != null)
return GenerateCSharpManagedToNativeType(buildData, new TypeInfo(apiType.MarshalAs), caller);
if (apiType.IsScriptingObject || apiType.IsInterface)
return "IntPtr";
}
@@ -509,7 +511,11 @@ namespace Flax.Build.Bindings
}
else
{
returnValueType = GenerateCSharpNativeToManaged(buildData, functionInfo.ReturnType, caller);
var apiType = FindApiTypeInfo(buildData, functionInfo.ReturnType, caller);
if (apiType != null && apiType.MarshalAs != null)
returnValueType = GenerateCSharpNativeToManaged(buildData, new TypeInfo(apiType.MarshalAs), caller);
else
returnValueType = GenerateCSharpNativeToManaged(buildData, functionInfo.ReturnType, caller);
}
#if USE_NETCORE

View File

@@ -19,7 +19,7 @@ namespace Flax.Build.Bindings
partial class BindingsGenerator
{
private static readonly Dictionary<string, Type> TypeCache = new Dictionary<string, Type>();
private const int CacheVersion = 19;
private const int CacheVersion = 20;
internal static void Write(BinaryWriter writer, string e)
{

View File

@@ -582,6 +582,9 @@ namespace Flax.Build.Bindings
{
CppReferencesFiles.Add(apiType.File);
if (apiType.MarshalAs != null)
return GenerateCppWrapperNativeToManaged(buildData, new TypeInfo(apiType.MarshalAs), caller, out type, functionInfo);
// Scripting Object
if (apiType.IsScriptingObject)
{
@@ -791,6 +794,9 @@ namespace Flax.Build.Bindings
if (apiType != null)
{
if (apiType.MarshalAs != null)
return GenerateCppWrapperManagedToNative(buildData, new TypeInfo(apiType.MarshalAs), caller, out type, out apiType, functionInfo, out needLocalVariable);
// Scripting Object (for non-pod types converting only, other API converts managed to unmanaged object in C# wrapper code)
if (CppNonPodTypesConvertingGeneration && apiType.IsScriptingObject && typeInfo.IsPtr)
{
@@ -2370,7 +2376,9 @@ namespace Flax.Build.Bindings
CppUsedNonPodTypes.Add(structureInfo);
contents.AppendLine(" static MObject* Box(void* ptr)");
contents.AppendLine(" {");
if (structureInfo.IsPod)
if (structureInfo.MarshalAs != null)
contents.AppendLine($" MISSING_CODE(\"Boxing native type {structureInfo.Name} as {structureInfo.MarshalAs}\"); return nullptr;"); // TODO: impl this
else if (structureInfo.IsPod)
contents.AppendLine($" return MCore::Object::Box(ptr, {structureTypeNameNative}::TypeInitializer.GetClass());");
else
contents.AppendLine($" return MUtils::Box(*({structureTypeNameNative}*)ptr, {structureTypeNameNative}::TypeInitializer.GetClass());");
@@ -2379,7 +2387,9 @@ namespace Flax.Build.Bindings
// Unboxing structures from managed object to native data
contents.AppendLine(" static void Unbox(void* ptr, MObject* managed)");
contents.AppendLine(" {");
if (structureInfo.IsPod)
if (structureInfo.MarshalAs != null)
contents.AppendLine($" MISSING_CODE(\"Boxing native type {structureInfo.Name} as {structureInfo.MarshalAs}\");"); // TODO: impl this
else if (structureInfo.IsPod)
contents.AppendLine($" Platform::MemoryCopy(ptr, MCore::Object::Unbox(managed), sizeof({structureTypeNameNative}));");
else
contents.AppendLine($" *({structureTypeNameNative}*)ptr = ToNative(*({GenerateCppManagedWrapperName(structureInfo)}*)MCore::Object::Unbox(managed));");
@@ -2657,6 +2667,13 @@ namespace Flax.Build.Bindings
{
if (CppUsedNonPodTypesList.Contains(apiType))
return;
if (apiType is ClassStructInfo classStructInfo)
{
if (classStructInfo.MarshalAs != null)
return;
if (classStructInfo.IsTemplate)
throw new Exception($"Cannot use template type '{classStructInfo}' as non-POD type for cross-language bindings.");
}
if (apiType is StructureInfo structureInfo)
{
// Check all fields (if one of them is also non-POD structure then we need to generate wrappers for them too)
@@ -2679,11 +2696,6 @@ namespace Flax.Build.Bindings
}
}
}
if (apiType is ClassStructInfo classStructInfo)
{
if (classStructInfo.IsTemplate)
throw new Exception($"Cannot use template type '{classStructInfo}' as non-POD type for cross-language bindings.");
}
CppUsedNonPodTypesList.Add(apiType);
}

View File

@@ -628,6 +628,9 @@ namespace Flax.Build.Bindings
case "namespace":
desc.Namespace = tag.Value;
break;
case "marshalas":
desc.MarshalAs = tag.Value;
break;
case "tag":
ParseTag(ref desc.Tags, tag);
break;
@@ -1202,6 +1205,9 @@ namespace Flax.Build.Bindings
case "namespace":
desc.Namespace = tag.Value;
break;
case "marshalas":
desc.MarshalAs = tag.Value;
break;
case "tag":
ParseTag(ref desc.Tags, tag);
break;