Skip to content

Commit

Permalink
Support opaque records
Browse files Browse the repository at this point in the history
  • Loading branch information
badcel committed Sep 1, 2023
1 parent 7ac07dd commit e2d752e
Show file tree
Hide file tree
Showing 96 changed files with 1,705 additions and 264 deletions.
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

0 comments on commit e2d752e

Please sign in to comment.