Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support opaque records #908

Merged
merged 1 commit into from
Sep 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/Generation/Generator/Generator/Internal/OpaqueTypedRecord.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Generator.Model;

namespace Generator.Generator.Internal;

internal class OpaqueTypedRecord : Generator<GirModel.Record>
{
private readonly Publisher _publisher;

public OpaqueTypedRecord(Publisher publisher)
{
_publisher = publisher;
}

public void Generate(GirModel.Record obj)
{
if (!Record.IsOpaqueTyped(obj))
return;

var source = Renderer.Internal.OpaqueTypedRecord.Render(obj);
var codeUnit = new CodeUnit(
Project: Namespace.GetCanonicalName(obj.Namespace),
Name: obj.Name,
Source: source,
IsInternal: true
);

_publisher.Publish(codeUnit);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Generator.Model;

namespace Generator.Generator.Internal;

internal class OpaqueTypedRecordHandle : Generator<GirModel.Record>
{
private readonly Publisher _publisher;

public OpaqueTypedRecordHandle(Publisher publisher)
{
_publisher = publisher;
}

public void Generate(GirModel.Record obj)
{
if (!Record.IsOpaqueTyped(obj))
return;

var source = Renderer.Internal.OpaqueTypedRecordHandle.Render(obj);
var codeUnit = new CodeUnit(
Project: Namespace.GetCanonicalName(obj.Namespace),
Name: Model.OpaqueTypedRecord.GetInternalHandle(obj),
Source: source,
IsInternal: true
);

_publisher.Publish(codeUnit);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ public RecordDelegates(Publisher publisher)

public void Generate(GirModel.Record record)
{
if (Record.IsOpaqueTyped(record))
return;

if (!record.Fields.Any(field => field.AnyTypeOrCallback.IsT1))
return;

Expand Down
3 changes: 3 additions & 0 deletions src/Generation/Generator/Generator/Internal/RecordHandle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ public RecordHandle(Publisher publisher)

public void Generate(GirModel.Record record)
{
if (Record.IsOpaqueTyped(record))
return;

var source = Renderer.Internal.RecordHandle.Render(record);
var codeUnit = new CodeUnit(
Project: Namespace.GetCanonicalName(record.Namespace),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ public RecordManagedHandle(Publisher publisher)

public void Generate(GirModel.Record record)
{
if (Record.IsOpaqueTyped(record))
return;

var source = Renderer.Internal.RecordManagedHandle.Render(record);
var codeUnit = new CodeUnit(
Project: Namespace.GetCanonicalName(record.Namespace),
Expand Down
4 changes: 3 additions & 1 deletion src/Generation/Generator/Generator/Internal/RecordMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ public RecordMethods(Publisher publisher)

public void Generate(GirModel.Record record)
{
if (Record.IsOpaqueTyped(record))
return;

if (!record.Constructors.Any()
&& !record.Methods.Any()
&& !record.Functions.Any()
&& record.TypeFunction is null)
return;


var source = Renderer.Internal.RecordMethods.Render(record);
var codeUnit = new CodeUnit(
Project: Namespace.GetCanonicalName(record.Namespace),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ public RecordOwnedHandle(Publisher publisher)

public void Generate(GirModel.Record record)
{
if (Record.IsOpaqueTyped(record))
return;

var source = Renderer.Internal.RecordOwnedHandle.Render(record);
var codeUnit = new CodeUnit(
Project: Namespace.GetCanonicalName(record.Namespace),
Expand Down
3 changes: 3 additions & 0 deletions src/Generation/Generator/Generator/Internal/RecordStruct.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ public RecordStruct(Publisher publisher)

public void Generate(GirModel.Record record)
{
if (Record.IsOpaqueTyped(record))
return;

var source = Renderer.Internal.RecordStruct.Render(record);
var codeUnit = new CodeUnit(
Project: Namespace.GetCanonicalName(record.Namespace),
Expand Down
29 changes: 29 additions & 0 deletions src/Generation/Generator/Generator/Public/OpaqueTypedRecord.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Generator.Model;

namespace Generator.Generator.Public;

internal class OpaqueTypedRecord : Generator<GirModel.Record>
{
private readonly Publisher _publisher;

public OpaqueTypedRecord(Publisher publisher)
{
_publisher = publisher;
}

public void Generate(GirModel.Record record)
{
if (!Record.IsOpaqueTyped(record))
return;

var source = Renderer.Public.OpaqueTypedRecord.Render(record);
var codeUnit = new CodeUnit(
Project: Namespace.GetCanonicalName(record.Namespace),
Name: Record.GetPublicClassName(record),
Source: source,
IsInternal: false
);

_publisher.Publish(codeUnit);
}
}
3 changes: 3 additions & 0 deletions src/Generation/Generator/Generator/Public/RecordClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ public RecordClass(Publisher publisher)

public void Generate(GirModel.Record record)
{
if (Record.IsOpaqueTyped(record))
return;

var source = Renderer.Public.RecordClass.Render(record);
var codeUnit = new CodeUnit(
Project: Namespace.GetCanonicalName(record.Namespace),
Expand Down
13 changes: 13 additions & 0 deletions src/Generation/Generator/Model/Function.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ namespace Generator.Model;

internal static partial class Function
{
public const string GetGType = "GetGType";

public static string GetName(GirModel.Function function)
{
if (function.Shadows is null)
Expand All @@ -17,4 +19,15 @@ public static string GetName(GirModel.Function function)

return function.Name.ToPascalCase().EscapeIdentifier();
}

public static string GetImportResolver(GirModel.Function function)
{
return function switch
{
//TODO Workaround as long as GObject and GLib are split up. GLib contains the e.g. "Bytes" record
//but the type definition is part of GObject. Therefore the GetGType function is part of GObject.
{ Parent.Namespace.Name: "GLib", Name: GetGType } => "GObject.Internal.ImportResolver.Library",
_ => "ImportResolver.Library"
};
}
}
34 changes: 34 additions & 0 deletions src/Generation/Generator/Model/OpaqueTypedRecord.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
namespace Generator.Model;

internal static class OpaqueTypedRecord
{
public static string GetPublicClassName(GirModel.Record record)
=> record.Name;

public static string GetFullyQualifiedPublicClassName(GirModel.Record record)
=> Namespace.GetPublicName(record.Namespace) + "." + GetPublicClassName(record);

public static string GetFullyQualifiedInternalClassName(GirModel.Record record)
=> Namespace.GetInternalName(record.Namespace) + "." + record.Name;

public static string GetInternalHandle(GirModel.Record record)
=> $"{Type.GetName(record)}Handle";

public static string GetInternalOwnedHandle(GirModel.Record record)
=> $"{Type.GetName(record)}OwnedHandle";

public static string GetInternalUnownedHandle(GirModel.Record record)
=> $"{Type.GetName(record)}UnownedHandle";

public static string GetFullyQuallifiedInternalHandle(GirModel.Record record)
=> $"{Namespace.GetInternalName(record.Namespace)}.{GetInternalHandle(record)}";

public static string GetFullyQuallifiedOwnedHandle(GirModel.Record record)
=> $"{Namespace.GetInternalName(record.Namespace)}.{GetInternalOwnedHandle(record)}";

public static string GetFullyQuallifiedUnownedHandle(GirModel.Record record)
=> $"{Namespace.GetInternalName(record.Namespace)}.{GetInternalUnownedHandle(record)}";

public static string GetFullyQuallifiedNullHandle(GirModel.Record record)
=> $"{Namespace.GetInternalName(record.Namespace)}.{GetInternalUnownedHandle(record)}.NullHandle";
}
8 changes: 8 additions & 0 deletions src/Generation/Generator/Model/Record.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

internal static partial class Record
{
public static bool IsOpaqueTyped(GirModel.Record record)
{
//Even if there is a TypeFunction it does not mean that it actually is
//a typed / boxed record. There is a magic keyword "intern" which means this
//record is actually fundamental and does not have a type function.
return record is { Opaque: true, TypeFunction.CIdentifier: not "intern" };
}

public static string GetFullyQualifiedInternalStructName(GirModel.Record record)
=> Namespace.GetInternalName(record.Namespace) + "." + GetInternalStructName(record);

Expand Down
6 changes: 6 additions & 0 deletions src/Generation/Generator/Records.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ public static void Generate(IEnumerable<GirModel.Record> records, string path)
var publisher = new Publisher(path);
var generators = new List<Generator<GirModel.Record>>()
{
//Opaque typed records
new Generator.Internal.OpaqueTypedRecord(publisher),
new Generator.Internal.OpaqueTypedRecordHandle(publisher),
new Generator.Public.OpaqueTypedRecord(publisher),

//Regular records
new Generator.Internal.RecordDelegates(publisher),
new Generator.Internal.RecordHandle(publisher),
new Generator.Internal.RecordOwnedHandle(publisher),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
using Generator.Model;
using System;
using Generator.Model;

namespace Generator.Renderer.Internal;

internal static class CallbackDelegate
{
public static string Render(GirModel.Callback callback)
{
return $@"
try
{
return $@"
using System;
using System.Runtime.InteropServices;

Expand All @@ -18,5 +21,12 @@ namespace {Namespace.GetInternalName(callback.Namespace)}

public delegate {ReturnTypeRendererCallback.Render(callback.ReturnType)} {callback.Name}({CallbackParameters.Render(callback.Parameters)}{Error.RenderCallback(callback)});
}}";
}
catch (Exception ex)
{
Log.Warning($"Did not generate callback delegatre '{callback.Name}': {ex.Message}");

return string.Empty;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ private static void Register<T>(Func<nuint> getType, params OSPlatform[] support

private static string RenderRegistration(GirModel.ComplexType type)
{
return @$"Register<{ComplexType.GetFullyQualified(type)}>(Internal.{type.Name}.GetGType{RenderPlatforms(type as GirModel.PlatformDependent)});";
return @$"Register<{ComplexType.GetFullyQualified(type)}>(Internal.{type.Name}.{Function.GetGType}{RenderPlatforms(type as GirModel.PlatformDependent)});";
}

private static string RenderPlatforms(GirModel.PlatformDependent? platformDependent)
Expand Down
2 changes: 1 addition & 1 deletion src/Generation/Generator/Renderer/Internal/Functions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public static string Render(GirModel.Function? function)
{DocComments.Render(function.ReturnType)}
{PlatformSupportAttribute.Render(function as GirModel.PlatformDependent)}
{VersionAttribute.Render(function.Version)}
[DllImport(ImportResolver.Library, EntryPoint = ""{function.CIdentifier}"")]
[DllImport({Function.GetImportResolver(function)}, EntryPoint = ""{function.CIdentifier}"")]
public static extern {ReturnTypeRenderer.Render(function.ReturnType)} {Function.GetName(function)}({Parameters.Render(function.Parameters)}{Error.Render(function)});";
}
catch (Exception ex)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace Generator.Renderer.Internal.InstanceParameter;

internal class OpaqueTypedRecord : InstanceParameterConverter
{
public bool Supports(GirModel.Type type)
{
return type is GirModel.Record r && Model.Record.IsOpaqueTyped(r);
}

public RenderableInstanceParameter Convert(GirModel.InstanceParameter instanceParameter)
{
return new RenderableInstanceParameter(
Name: Model.InstanceParameter.GetName(instanceParameter),
NullableTypeName: GetNullableTypeName(instanceParameter)
);
}

private static string GetNullableTypeName(GirModel.InstanceParameter instanceParameter)
{
var type = (GirModel.Record) instanceParameter.Type;
return instanceParameter switch
{
{ Direction: GirModel.Direction.In, Transfer: GirModel.Transfer.None } => Model.OpaqueTypedRecord.GetFullyQuallifiedInternalHandle(type),
{ Direction: GirModel.Direction.In, Transfer: GirModel.Transfer.Full } => Model.OpaqueTypedRecord.GetFullyQuallifiedUnownedHandle(type),
_ => throw new System.Exception($"Can't detect opaque record instance parameter type {instanceParameter.Name}: CallerAllocates={instanceParameter.CallerAllocates} Direction={instanceParameter.Direction} Transfer={instanceParameter.Transfer}")
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ internal class Record : InstanceParameterConverter
{
public bool Supports(GirModel.Type type)
{
return type is GirModel.Record;
return type is GirModel.Record r && !Model.Record.IsOpaqueTyped(r);
}

public RenderableInstanceParameter Convert(GirModel.InstanceParameter instanceParameter)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ internal static class InstanceParameters
{
new InstanceParameter.Class(),
new InstanceParameter.Interface(),
new InstanceParameter.OpaqueTypedRecord(),
new InstanceParameter.Pointer(),
new InstanceParameter.Record(),
new InstanceParameter.Union()
Expand Down
37 changes: 37 additions & 0 deletions src/Generation/Generator/Renderer/Internal/OpaqueTypedRecord.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Generator.Model;

namespace Generator.Renderer.Internal;

internal static class OpaqueTypedRecord
{
public static string Render(GirModel.Record record)
{
return $@"
using System;
using GObject;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;

#nullable enable

namespace {Namespace.GetInternalName(record.Namespace)};

// AUTOGENERATED FILE - DO NOT MODIFY

{PlatformSupportAttribute.Render(record as GirModel.PlatformDependent)}
public partial class {record.Name} {RenderNativeGTypeProvider(record)}
{{
{Constructors.Render(record.Constructors)}
{Functions.Render(record.TypeFunction)}
{Functions.Render(record.Functions)}
{Methods.Render(record.Methods)}
}}";
}

private static string RenderNativeGTypeProvider(GirModel.Record record)
{
return record.TypeFunction is not null
? ": GLib.Internal.NativeGTypeProvider"
: string.Empty;
}
}
Loading
Loading