From e2d752e0202b1bd83a86125c1dc1fd3631a83db2 Mon Sep 17 00:00:00 2001 From: badcel <1218031+badcel@users.noreply.github.com> Date: Wed, 26 Jul 2023 12:27:02 +0200 Subject: [PATCH] Support opaque records --- .../Generator/Internal/OpaqueTypedRecord.cs | 29 ++ .../Internal/OpaqueTypedRecordHandle.cs | 29 ++ .../Generator/Internal/RecordDelegates.cs | 3 + .../Generator/Internal/RecordHandle.cs | 3 + .../Generator/Internal/RecordManagedHandle.cs | 3 + .../Generator/Internal/RecordMethods.cs | 4 +- .../Generator/Internal/RecordOwnedHandle.cs | 3 + .../Generator/Internal/RecordStruct.cs | 3 + .../Generator/Public/OpaqueTypedRecord.cs | 29 ++ .../Generator/Generator/Public/RecordClass.cs | 3 + src/Generation/Generator/Model/Function.cs | 13 + .../Generator/Model/OpaqueTypedRecord.cs | 34 ++ src/Generation/Generator/Model/Record.cs | 8 + src/Generation/Generator/Records.cs | 6 + .../Internal/Callback/CallbackDelegate.cs | 14 +- .../Framework/FrameworkTypeRegistration.cs | 2 +- .../Generator/Renderer/Internal/Functions.cs | 2 +- .../Converter/OpaqueTypedRecord.cs | 28 ++ .../InstanceParameter/Converter/Record.cs | 2 +- .../InstanceParameter/InstanceParameters.cs | 1 + .../Renderer/Internal/OpaqueTypedRecord.cs | 37 ++ .../Internal/OpaqueTypedRecordHandle.cs | 103 ++++++ .../Internal/Parameter/CallbackParameters.cs | 5 +- .../Parameter/Converter/OpaqueTypedRecord.cs | 45 +++ .../Converter/OpaqueTypedRecordArray.cs | 27 ++ .../Converter/OpaqueTypedRecordCallback.cs | 30 ++ .../Internal/Parameter/Converter/Record.cs | 4 +- .../Parameter/Converter/RecordAlias.cs | 4 +- ...PointerAlias.cs => RecordAliasCallback.cs} | 4 +- .../Parameter/Converter/RecordArray.cs | 2 +- .../{RecordAsPointer.cs => RecordCallback.cs} | 4 +- .../Parameter/Converter/RecordGLibPtrArray.cs | 2 +- .../Renderer/Internal/Parameter/Parameters.cs | 2 + .../Converter/OpaqueTypedRecord.cs | 36 ++ .../Converter/Record.cs | 2 +- .../Converter/RecordArray.cs | 2 +- .../ParameterToManagedExpression.cs | 1 + .../ReturnType/Converter/OpaqueTypedRecord.cs | 25 ++ .../Converter/OpaqueTypedRecordCallback.cs | 14 + .../Internal/ReturnType/Converter/Record.cs | 2 +- .../ReturnType/Converter/RecordArray.cs | 2 +- .../ReturnType/Converter/RecordInCallback.cs | 2 +- .../Internal/ReturnType/ReturnTypeRenderer.cs | 1 + .../ReturnType/ReturnTypeRendererCallback.cs | 1 + .../Converter/OpaqueTypedRecord.cs | 21 ++ .../Converter/Record.cs | 2 +- .../ReturnTypeToNativeExpression.cs | 1 + .../Public/Constructor/ConstructorData.cs | 2 +- .../Public/Constructor/ConstructorRenderer.cs | 7 +- .../Public/Constructor/Converter/Class.cs | 3 +- .../Converter/OpaqueTypedRecord.cs | 32 ++ .../Renderer/Public/FunctionRenderer.cs | 6 +- .../Converter/OpaqueTypedRecord.cs | 21 ++ .../InstanceParameterToNativeExpression.cs | 1 + .../Renderer/Public/OpaqueTypedRecord.cs | 56 +++ .../Parameter/Converter/OpaqueTypedRecord.cs | 31 ++ .../Converter/OpaqueTypedRecordArray.cs | 31 ++ .../Public/Parameter/Converter/Record.cs | 2 +- .../Public/Parameter/Converter/RecordArray.cs | 2 +- .../Public/Parameter/ParameterRenderer.cs | 2 + .../Converter/OpaqueTypedRecord.cs | 33 ++ .../Converter/OpaqueTypedRecordArray.cs | 71 ++++ .../Converter/Record.cs | 2 +- .../Converter/RecordArray.cs | 2 +- .../ParameterToNativeExpression.cs | 2 + .../ReturnType/Converter/OpaqueTypedRecord.cs | 16 + .../Public/ReturnType/Converter/Record.cs | 2 +- .../ReturnType/Converter/RecordArray.cs | 2 +- .../Public/ReturnType/ReturnTypeRenderer.cs | 1 + .../ReturnType/ReturnTypeRendererCallback.cs | 1 + .../Converter/OpaqueTypedRecord.cs | 28 ++ .../Converter/Record.cs | 2 +- .../ReturnTypeToManagedExpression.cs | 1 + src/Generation/GirModel/AnyType.cs | 42 ++- src/Libs/GLib-2.0/GLib-2.0.csproj | 2 +- .../{Internal => GObject}/Functions.cs | 4 +- src/Libs/GLib-2.0/Internal/BoxedHandle.cs | 46 --- src/Libs/GLib-2.0/Public/Bytes.cs | 18 +- src/Libs/GLib-2.0/Public/MainContext.cs | 12 - src/Libs/GLib-2.0/Public/MainLoop.cs | 21 -- src/Libs/GLib-2.0/Public/Variant.cs | 6 - src/Libs/GLib-2.0/Public/VariantType.cs | 22 +- src/Libs/GdkPixbuf-2.0/Public/PixbufLoader.cs | 2 +- src/Libs/Gio-2.0/Public/DBusConnection.cs | 16 +- .../GirTestLib/girtest-opaque-record-tester.c | 62 ---- .../GirTestLib/girtest-opaque-record-tester.h | 16 - .../girtest-opaque-typed-record-tester.c | 339 ++++++++++++++++++ .../girtest-opaque-typed-record-tester.h | 86 +++++ src/Native/GirTestLib/girtest.h | 2 +- src/Native/GirTestLib/meson.build | 4 +- .../DBusNotification/SendNotification.cs | 5 +- .../GLib-2.0.Tests/Records/VariantTypeTest.cs | 2 +- .../SynchronizationContextTest.cs | 4 +- .../GObject-2.0.Tests/Records/ValueTest.cs | 5 +- .../Libs/Gio-2.0.Tests/SimpleActionTest.cs | 4 +- .../OpaqueTypedRecordTest.cs | 290 +++++++++++++++ 96 files changed, 1705 insertions(+), 264 deletions(-) create mode 100644 src/Generation/Generator/Generator/Internal/OpaqueTypedRecord.cs create mode 100644 src/Generation/Generator/Generator/Internal/OpaqueTypedRecordHandle.cs create mode 100644 src/Generation/Generator/Generator/Public/OpaqueTypedRecord.cs create mode 100644 src/Generation/Generator/Model/OpaqueTypedRecord.cs create mode 100644 src/Generation/Generator/Renderer/Internal/InstanceParameter/Converter/OpaqueTypedRecord.cs create mode 100644 src/Generation/Generator/Renderer/Internal/OpaqueTypedRecord.cs create mode 100644 src/Generation/Generator/Renderer/Internal/OpaqueTypedRecordHandle.cs create mode 100644 src/Generation/Generator/Renderer/Internal/Parameter/Converter/OpaqueTypedRecord.cs create mode 100644 src/Generation/Generator/Renderer/Internal/Parameter/Converter/OpaqueTypedRecordArray.cs create mode 100644 src/Generation/Generator/Renderer/Internal/Parameter/Converter/OpaqueTypedRecordCallback.cs rename src/Generation/Generator/Renderer/Internal/Parameter/Converter/{RecordAsPointerAlias.cs => RecordAliasCallback.cs} (72%) rename src/Generation/Generator/Renderer/Internal/Parameter/Converter/{RecordAsPointer.cs => RecordCallback.cs} (80%) create mode 100644 src/Generation/Generator/Renderer/Internal/ParameterToManagedExpression/Converter/OpaqueTypedRecord.cs create mode 100644 src/Generation/Generator/Renderer/Internal/ReturnType/Converter/OpaqueTypedRecord.cs create mode 100644 src/Generation/Generator/Renderer/Internal/ReturnType/Converter/OpaqueTypedRecordCallback.cs create mode 100644 src/Generation/Generator/Renderer/Internal/ReturnTypeToNativeExpression/Converter/OpaqueTypedRecord.cs create mode 100644 src/Generation/Generator/Renderer/Public/Constructor/Converter/OpaqueTypedRecord.cs create mode 100644 src/Generation/Generator/Renderer/Public/InstanceParameterToNativeExpression/Converter/OpaqueTypedRecord.cs create mode 100644 src/Generation/Generator/Renderer/Public/OpaqueTypedRecord.cs create mode 100644 src/Generation/Generator/Renderer/Public/Parameter/Converter/OpaqueTypedRecord.cs create mode 100644 src/Generation/Generator/Renderer/Public/Parameter/Converter/OpaqueTypedRecordArray.cs create mode 100644 src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/OpaqueTypedRecord.cs create mode 100644 src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/OpaqueTypedRecordArray.cs create mode 100644 src/Generation/Generator/Renderer/Public/ReturnType/Converter/OpaqueTypedRecord.cs create mode 100644 src/Generation/Generator/Renderer/Public/ReturnTypeToManagedExpression/Converter/OpaqueTypedRecord.cs rename src/Libs/GLib-2.0/{Internal => GObject}/Functions.cs (88%) delete mode 100644 src/Libs/GLib-2.0/Internal/BoxedHandle.cs delete mode 100644 src/Libs/GLib-2.0/Public/MainContext.cs delete mode 100644 src/Native/GirTestLib/girtest-opaque-record-tester.c delete mode 100644 src/Native/GirTestLib/girtest-opaque-record-tester.h create mode 100644 src/Native/GirTestLib/girtest-opaque-typed-record-tester.c create mode 100644 src/Native/GirTestLib/girtest-opaque-typed-record-tester.h create mode 100644 src/Tests/Libs/GirTest-0.1.Tests/OpaqueTypedRecordTest.cs diff --git a/src/Generation/Generator/Generator/Internal/OpaqueTypedRecord.cs b/src/Generation/Generator/Generator/Internal/OpaqueTypedRecord.cs new file mode 100644 index 000000000..779ac411b --- /dev/null +++ b/src/Generation/Generator/Generator/Internal/OpaqueTypedRecord.cs @@ -0,0 +1,29 @@ +using Generator.Model; + +namespace Generator.Generator.Internal; + +internal class OpaqueTypedRecord : Generator +{ + 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); + } +} diff --git a/src/Generation/Generator/Generator/Internal/OpaqueTypedRecordHandle.cs b/src/Generation/Generator/Generator/Internal/OpaqueTypedRecordHandle.cs new file mode 100644 index 000000000..ea8907f69 --- /dev/null +++ b/src/Generation/Generator/Generator/Internal/OpaqueTypedRecordHandle.cs @@ -0,0 +1,29 @@ +using Generator.Model; + +namespace Generator.Generator.Internal; + +internal class OpaqueTypedRecordHandle : Generator +{ + 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); + } +} diff --git a/src/Generation/Generator/Generator/Internal/RecordDelegates.cs b/src/Generation/Generator/Generator/Internal/RecordDelegates.cs index 3a9e3f279..3e7a2e4db 100644 --- a/src/Generation/Generator/Generator/Internal/RecordDelegates.cs +++ b/src/Generation/Generator/Generator/Internal/RecordDelegates.cs @@ -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; diff --git a/src/Generation/Generator/Generator/Internal/RecordHandle.cs b/src/Generation/Generator/Generator/Internal/RecordHandle.cs index 5dc6ccc8a..fe1e3625d 100644 --- a/src/Generation/Generator/Generator/Internal/RecordHandle.cs +++ b/src/Generation/Generator/Generator/Internal/RecordHandle.cs @@ -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), diff --git a/src/Generation/Generator/Generator/Internal/RecordManagedHandle.cs b/src/Generation/Generator/Generator/Internal/RecordManagedHandle.cs index 3b4ff66e7..06ec1f118 100644 --- a/src/Generation/Generator/Generator/Internal/RecordManagedHandle.cs +++ b/src/Generation/Generator/Generator/Internal/RecordManagedHandle.cs @@ -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), diff --git a/src/Generation/Generator/Generator/Internal/RecordMethods.cs b/src/Generation/Generator/Generator/Internal/RecordMethods.cs index 309173d7b..2d7d48f93 100644 --- a/src/Generation/Generator/Generator/Internal/RecordMethods.cs +++ b/src/Generation/Generator/Generator/Internal/RecordMethods.cs @@ -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), diff --git a/src/Generation/Generator/Generator/Internal/RecordOwnedHandle.cs b/src/Generation/Generator/Generator/Internal/RecordOwnedHandle.cs index cbb4d3c77..9470a8c97 100644 --- a/src/Generation/Generator/Generator/Internal/RecordOwnedHandle.cs +++ b/src/Generation/Generator/Generator/Internal/RecordOwnedHandle.cs @@ -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), diff --git a/src/Generation/Generator/Generator/Internal/RecordStruct.cs b/src/Generation/Generator/Generator/Internal/RecordStruct.cs index 72026d9e6..d8504cec1 100644 --- a/src/Generation/Generator/Generator/Internal/RecordStruct.cs +++ b/src/Generation/Generator/Generator/Internal/RecordStruct.cs @@ -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), diff --git a/src/Generation/Generator/Generator/Public/OpaqueTypedRecord.cs b/src/Generation/Generator/Generator/Public/OpaqueTypedRecord.cs new file mode 100644 index 000000000..1f7f67870 --- /dev/null +++ b/src/Generation/Generator/Generator/Public/OpaqueTypedRecord.cs @@ -0,0 +1,29 @@ +using Generator.Model; + +namespace Generator.Generator.Public; + +internal class OpaqueTypedRecord : Generator +{ + 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); + } +} diff --git a/src/Generation/Generator/Generator/Public/RecordClass.cs b/src/Generation/Generator/Generator/Public/RecordClass.cs index 461ddbea2..75ff0cff9 100644 --- a/src/Generation/Generator/Generator/Public/RecordClass.cs +++ b/src/Generation/Generator/Generator/Public/RecordClass.cs @@ -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), diff --git a/src/Generation/Generator/Model/Function.cs b/src/Generation/Generator/Model/Function.cs index f70da64c0..6816eef9b 100644 --- a/src/Generation/Generator/Model/Function.cs +++ b/src/Generation/Generator/Model/Function.cs @@ -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) @@ -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" + }; + } } diff --git a/src/Generation/Generator/Model/OpaqueTypedRecord.cs b/src/Generation/Generator/Model/OpaqueTypedRecord.cs new file mode 100644 index 000000000..5bed0845d --- /dev/null +++ b/src/Generation/Generator/Model/OpaqueTypedRecord.cs @@ -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"; +} diff --git a/src/Generation/Generator/Model/Record.cs b/src/Generation/Generator/Model/Record.cs index 5e1a9e404..d7442b393 100644 --- a/src/Generation/Generator/Model/Record.cs +++ b/src/Generation/Generator/Model/Record.cs @@ -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); diff --git a/src/Generation/Generator/Records.cs b/src/Generation/Generator/Records.cs index 7d4669631..6d96f7e09 100644 --- a/src/Generation/Generator/Records.cs +++ b/src/Generation/Generator/Records.cs @@ -12,6 +12,12 @@ public static void Generate(IEnumerable records, string path) var publisher = new Publisher(path); var generators = new List>() { + //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), diff --git a/src/Generation/Generator/Renderer/Internal/Callback/CallbackDelegate.cs b/src/Generation/Generator/Renderer/Internal/Callback/CallbackDelegate.cs index 252adc5f8..a6954d9e7 100644 --- a/src/Generation/Generator/Renderer/Internal/Callback/CallbackDelegate.cs +++ b/src/Generation/Generator/Renderer/Internal/Callback/CallbackDelegate.cs @@ -1,4 +1,5 @@ -using Generator.Model; +using System; +using Generator.Model; namespace Generator.Renderer.Internal; @@ -6,7 +7,9 @@ internal static class CallbackDelegate { public static string Render(GirModel.Callback callback) { - return $@" + try + { + return $@" using System; using System.Runtime.InteropServices; @@ -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; + } } } diff --git a/src/Generation/Generator/Renderer/Internal/Framework/FrameworkTypeRegistration.cs b/src/Generation/Generator/Renderer/Internal/Framework/FrameworkTypeRegistration.cs index 64a4d5ee8..9047ca51e 100644 --- a/src/Generation/Generator/Renderer/Internal/Framework/FrameworkTypeRegistration.cs +++ b/src/Generation/Generator/Renderer/Internal/Framework/FrameworkTypeRegistration.cs @@ -57,7 +57,7 @@ private static void Register(Func 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) diff --git a/src/Generation/Generator/Renderer/Internal/Functions.cs b/src/Generation/Generator/Renderer/Internal/Functions.cs index d1353b445..e962a62b3 100644 --- a/src/Generation/Generator/Renderer/Internal/Functions.cs +++ b/src/Generation/Generator/Renderer/Internal/Functions.cs @@ -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) diff --git a/src/Generation/Generator/Renderer/Internal/InstanceParameter/Converter/OpaqueTypedRecord.cs b/src/Generation/Generator/Renderer/Internal/InstanceParameter/Converter/OpaqueTypedRecord.cs new file mode 100644 index 000000000..0db3ef2d5 --- /dev/null +++ b/src/Generation/Generator/Renderer/Internal/InstanceParameter/Converter/OpaqueTypedRecord.cs @@ -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}") + }; + } +} diff --git a/src/Generation/Generator/Renderer/Internal/InstanceParameter/Converter/Record.cs b/src/Generation/Generator/Renderer/Internal/InstanceParameter/Converter/Record.cs index fbe901d44..172c8a6cc 100644 --- a/src/Generation/Generator/Renderer/Internal/InstanceParameter/Converter/Record.cs +++ b/src/Generation/Generator/Renderer/Internal/InstanceParameter/Converter/Record.cs @@ -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) diff --git a/src/Generation/Generator/Renderer/Internal/InstanceParameter/InstanceParameters.cs b/src/Generation/Generator/Renderer/Internal/InstanceParameter/InstanceParameters.cs index f074a3822..3bce551dd 100644 --- a/src/Generation/Generator/Renderer/Internal/InstanceParameter/InstanceParameters.cs +++ b/src/Generation/Generator/Renderer/Internal/InstanceParameter/InstanceParameters.cs @@ -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() diff --git a/src/Generation/Generator/Renderer/Internal/OpaqueTypedRecord.cs b/src/Generation/Generator/Renderer/Internal/OpaqueTypedRecord.cs new file mode 100644 index 000000000..e68070ed0 --- /dev/null +++ b/src/Generation/Generator/Renderer/Internal/OpaqueTypedRecord.cs @@ -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; + } +} diff --git a/src/Generation/Generator/Renderer/Internal/OpaqueTypedRecordHandle.cs b/src/Generation/Generator/Renderer/Internal/OpaqueTypedRecordHandle.cs new file mode 100644 index 000000000..c04ea2e9d --- /dev/null +++ b/src/Generation/Generator/Renderer/Internal/OpaqueTypedRecordHandle.cs @@ -0,0 +1,103 @@ +using Generator.Model; + +namespace Generator.Renderer.Internal; + +internal static class OpaqueTypedRecordHandle +{ + public static string Render(GirModel.Record record) + { + var typeName = Model.OpaqueTypedRecord.GetInternalHandle(record); + var unownedHandleTypeName = Model.OpaqueTypedRecord.GetInternalUnownedHandle(record); + var ownedHandleTypeName = Model.OpaqueTypedRecord.GetInternalOwnedHandle(record); + var getGType = $"{Model.OpaqueTypedRecord.GetFullyQualifiedInternalClassName(record)}.{Function.GetGType}()"; + + 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 abstract class {typeName} : SafeHandle +{{ + public sealed override bool IsInvalid => handle == IntPtr.Zero; + + protected {typeName}(bool ownsHandle) : base(IntPtr.Zero, ownsHandle) {{ }} + + public {ownedHandleTypeName} OwnedCopy() + {{ + var ptr = GObject.Internal.Functions.BoxedCopy({getGType}, handle); + return new {ownedHandleTypeName}(ptr); + }} + + public {unownedHandleTypeName} UnownedCopy() + {{ + var ptr = GObject.Internal.Functions.BoxedCopy({getGType}, handle); + return new {unownedHandleTypeName}(ptr); + }} +}} + +public class {unownedHandleTypeName} : {typeName} +{{ + private static {unownedHandleTypeName}? nullHandle; + public static {unownedHandleTypeName} NullHandle => nullHandle ??= new {unownedHandleTypeName}(); + + /// + /// Creates a new instance of {unownedHandleTypeName}. Used automatically by PInvoke. + /// + internal {unownedHandleTypeName}() : base(false) {{ }} + + /// + /// Creates a new instance of {ownedHandleTypeName}. Assumes that the given pointer is unowned by the runtime. + /// + internal {unownedHandleTypeName}(IntPtr ptr) : base(false) + {{ + SetHandle(ptr); + }} + + protected override bool ReleaseHandle() + {{ + throw new Exception(""UnownedHandle must not be freed""); + }} +}} + +public class {ownedHandleTypeName} : {typeName} +{{ + /// + /// Creates a new instance of {ownedHandleTypeName}. Used automatically by PInvoke. + /// + internal {ownedHandleTypeName}() : base(true) {{ }} + + /// + /// Creates a new instance of {ownedHandleTypeName}. Assumes that the given pointer is owned by the runtime. + /// + internal {ownedHandleTypeName}(IntPtr ptr) : base(true) + {{ + SetHandle(ptr); + }} + + /// + /// Create a {ownedHandleTypeName} from a pointer that is assumed unowned. To do so a + /// boxed copy is created of the given pointer to be used as the handle. + /// + /// A pointer to a {record.Name} which is not owned by the runtime. + /// A {ownedHandleTypeName} + public static {ownedHandleTypeName} FromUnowned(IntPtr ptr) + {{ + var ownedPtr = GObject.Internal.Functions.BoxedCopy({getGType}, ptr); + return new {ownedHandleTypeName}(ownedPtr); + }} + + protected override bool ReleaseHandle() + {{ + GObject.Internal.Functions.BoxedFree({getGType}, handle); + return true; + }} +}}"; + } +} diff --git a/src/Generation/Generator/Renderer/Internal/Parameter/CallbackParameters.cs b/src/Generation/Generator/Renderer/Internal/Parameter/CallbackParameters.cs index 5192d24cd..63b3c450d 100644 --- a/src/Generation/Generator/Renderer/Internal/Parameter/CallbackParameters.cs +++ b/src/Generation/Generator/Renderer/Internal/Parameter/CallbackParameters.cs @@ -16,6 +16,7 @@ internal static class CallbackParameters new Parameter.Interface(), new Parameter.InterfaceArray(), new Parameter.NativeUnsignedIntegerArray(), + new Parameter.OpaqueTypedRecordCallback(), new Parameter.Pointer(), new Parameter.PointerAlias(), new Parameter.PointerArray(), @@ -28,9 +29,9 @@ internal static class CallbackParameters new Parameter.PrimitiveValueTypeGLibArray(), new Parameter.PrimitiveValueTypeGLibArrayAlias(), new Parameter.PrimitiveValueTypeGLibPtrArray(), + new Parameter.RecordAliasCallback(), //Callbacks do not support record safe handles in parameters new Parameter.RecordArray(), - new Parameter.RecordAsPointer(), //Callbacks do not support record safe handles in parameters - new Parameter.RecordAsPointerAlias(), //Callbacks do not support record safe handles in parameters + new Parameter.RecordCallback(), //Callbacks do not support record safe handles in parameters new Parameter.RecordGLibPtrArray(), new Parameter.String(), new Parameter.StringArray(), diff --git a/src/Generation/Generator/Renderer/Internal/Parameter/Converter/OpaqueTypedRecord.cs b/src/Generation/Generator/Renderer/Internal/Parameter/Converter/OpaqueTypedRecord.cs new file mode 100644 index 000000000..8c636f23b --- /dev/null +++ b/src/Generation/Generator/Renderer/Internal/Parameter/Converter/OpaqueTypedRecord.cs @@ -0,0 +1,45 @@ +using System; + +namespace Generator.Renderer.Internal.Parameter; + +internal class OpaqueTypedRecord : ParameterConverter +{ + public bool Supports(GirModel.AnyType anyType) + { + return anyType.Is(out var record) && Model.Record.IsOpaqueTyped(record); + } + + public RenderableParameter Convert(GirModel.Parameter parameter) + { + return new RenderableParameter( + Attribute: string.Empty, + Direction: GetDirection(parameter), + NullableTypeName: GetNullableTypeName(parameter), + Name: Model.Parameter.GetName(parameter) + ); + } + + private static string GetNullableTypeName(GirModel.Parameter parameter) + { + //Native opaque records are represented as SafeHandles and are not nullable + + var type = (GirModel.Record) parameter.AnyTypeOrVarArgs.AsT0.AsT0; + return parameter 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), + { Direction: GirModel.Direction.Out, Transfer: GirModel.Transfer.Full } => Model.OpaqueTypedRecord.GetFullyQuallifiedInternalHandle(type), + { Direction: GirModel.Direction.Out, Transfer: GirModel.Transfer.None } => Model.OpaqueTypedRecord.GetFullyQuallifiedInternalHandle(type), + _ => throw new Exception($"Can't detect opaque record parameter type {parameter.Name}: CallerAllocates={parameter.CallerAllocates} Direction={parameter.Direction} Transfer={parameter.Transfer}") + }; + } + + private static string GetDirection(GirModel.Parameter parameter) => parameter switch + { + { Direction: GirModel.Direction.In } => ParameterDirection.In(), + { Direction: GirModel.Direction.InOut } => ParameterDirection.In(), + { Direction: GirModel.Direction.Out, CallerAllocates: true } => ParameterDirection.In(), + { Direction: GirModel.Direction.Out } => ParameterDirection.Out(), + _ => throw new Exception($"Unknown parameter direction for opaque typed record parameter {parameter.Name}") + }; +} diff --git a/src/Generation/Generator/Renderer/Internal/Parameter/Converter/OpaqueTypedRecordArray.cs b/src/Generation/Generator/Renderer/Internal/Parameter/Converter/OpaqueTypedRecordArray.cs new file mode 100644 index 000000000..5cd290869 --- /dev/null +++ b/src/Generation/Generator/Renderer/Internal/Parameter/Converter/OpaqueTypedRecordArray.cs @@ -0,0 +1,27 @@ +using System; + +namespace Generator.Renderer.Internal.Parameter; + +internal class OpaqueTypedRecordArray : ParameterConverter +{ + public bool Supports(GirModel.AnyType anyType) + { + return anyType.IsArray(out var record) && Model.Record.IsOpaqueTyped(record); + } + + public RenderableParameter Convert(GirModel.Parameter parameter) + { + if (!parameter.AnyTypeOrVarArgs.AsT0.AsT1.IsPointer) + { + var record = (GirModel.Record) parameter.AnyTypeOrVarArgs.AsT0.AsT1.AnyType.AsT0; + throw new Exception($"Unpointed opaque record array of type {record.Name} not yet supported"); + } + + return new RenderableParameter( + Attribute: string.Empty, + Direction: string.Empty, + NullableTypeName: $"ref {Model.Type.Pointer}", + Name: Model.Parameter.GetName(parameter) + ); + } +} diff --git a/src/Generation/Generator/Renderer/Internal/Parameter/Converter/OpaqueTypedRecordCallback.cs b/src/Generation/Generator/Renderer/Internal/Parameter/Converter/OpaqueTypedRecordCallback.cs new file mode 100644 index 000000000..12935c6fb --- /dev/null +++ b/src/Generation/Generator/Renderer/Internal/Parameter/Converter/OpaqueTypedRecordCallback.cs @@ -0,0 +1,30 @@ +using System; + +namespace Generator.Renderer.Internal.Parameter; + +internal class OpaqueTypedRecordCallback : ParameterConverter +{ + public bool Supports(GirModel.AnyType anyType) + { + return anyType.Is(out var record) && Model.Record.IsOpaqueTyped(record); + } + + public RenderableParameter Convert(GirModel.Parameter parameter) + { + return new RenderableParameter( + Attribute: string.Empty, + Direction: GetDirection(parameter), + NullableTypeName: Model.Type.Pointer, + Name: Model.Parameter.GetName(parameter) + ); + } + + private static string GetDirection(GirModel.Parameter parameter) => parameter switch + { + { Direction: GirModel.Direction.In } => ParameterDirection.In(), + { Direction: GirModel.Direction.InOut } => ParameterDirection.In(), + { Direction: GirModel.Direction.Out, CallerAllocates: true } => ParameterDirection.In(), + { Direction: GirModel.Direction.Out } => ParameterDirection.Out(), + _ => throw new Exception("Unknown direction for opaque record parameter in callback") + }; +} diff --git a/src/Generation/Generator/Renderer/Internal/Parameter/Converter/Record.cs b/src/Generation/Generator/Renderer/Internal/Parameter/Converter/Record.cs index 1720fca6e..f155ac23d 100644 --- a/src/Generation/Generator/Renderer/Internal/Parameter/Converter/Record.cs +++ b/src/Generation/Generator/Renderer/Internal/Parameter/Converter/Record.cs @@ -4,7 +4,7 @@ internal class Record : ParameterConverter { public bool Supports(GirModel.AnyType anyType) { - return anyType.Is(); + return anyType.Is(out var record) && !Model.Record.IsOpaqueTyped(record); } public RenderableParameter Convert(GirModel.Parameter parameter) @@ -31,7 +31,7 @@ private static string GetNullableTypeName(GirModel.Parameter parameter) { CallerAllocates: false, Direction: GirModel.Direction.Out, Transfer: GirModel.Transfer.Full } => Model.Record.GetFullyQualifiedInternalOwnedHandle(type), { CallerAllocates: false, Direction: GirModel.Direction.Out, Transfer: GirModel.Transfer.Container } => Model.Record.GetFullyQualifiedInternalOwnedHandle(type), { CallerAllocates: false, Direction: GirModel.Direction.Out, Transfer: GirModel.Transfer.None } => Model.Record.GetFullyQualifiedInternalUnownedHandle(type), - _ => throw new System.Exception($"Can't detect parameter type: CallerAllocates={parameter.CallerAllocates} Direction={parameter.Direction} Transfer={parameter.Transfer}") + _ => throw new System.Exception($"Can't detect record parameter type {parameter.Name}: CallerAllocates={parameter.CallerAllocates} Direction={parameter.Direction} Transfer={parameter.Transfer}") }; } diff --git a/src/Generation/Generator/Renderer/Internal/Parameter/Converter/RecordAlias.cs b/src/Generation/Generator/Renderer/Internal/Parameter/Converter/RecordAlias.cs index 9d81cb568..aed87533c 100644 --- a/src/Generation/Generator/Renderer/Internal/Parameter/Converter/RecordAlias.cs +++ b/src/Generation/Generator/Renderer/Internal/Parameter/Converter/RecordAlias.cs @@ -4,7 +4,7 @@ internal class RecordAlias : ParameterConverter { public bool Supports(GirModel.AnyType anyType) { - return anyType.IsAlias(); + return anyType.IsAlias(out var record) && !Model.Record.IsOpaqueTyped(record); } public RenderableParameter Convert(GirModel.Parameter parameter) @@ -31,7 +31,7 @@ private static string GetNullableTypeName(GirModel.Parameter parameter) { CallerAllocates: false, Direction: GirModel.Direction.Out, Transfer: GirModel.Transfer.Full } => Model.Record.GetFullyQualifiedInternalOwnedHandle(type), { CallerAllocates: false, Direction: GirModel.Direction.Out, Transfer: GirModel.Transfer.Container } => Model.Record.GetFullyQualifiedInternalOwnedHandle(type), { CallerAllocates: false, Direction: GirModel.Direction.Out, Transfer: GirModel.Transfer.None } => Model.Record.GetFullyQualifiedInternalUnownedHandle(type), - _ => throw new System.Exception($"Can't detect parameter type: CallerAllocates={parameter.CallerAllocates} Direction={parameter.Direction} Transfer={parameter.Transfer}") + _ => throw new System.Exception($"Can't detect record alias parameter type {parameter.Name}: CallerAllocates={parameter.CallerAllocates} Direction={parameter.Direction} Transfer={parameter.Transfer}") }; } diff --git a/src/Generation/Generator/Renderer/Internal/Parameter/Converter/RecordAsPointerAlias.cs b/src/Generation/Generator/Renderer/Internal/Parameter/Converter/RecordAliasCallback.cs similarity index 72% rename from src/Generation/Generator/Renderer/Internal/Parameter/Converter/RecordAsPointerAlias.cs rename to src/Generation/Generator/Renderer/Internal/Parameter/Converter/RecordAliasCallback.cs index 5114d4682..f51d58933 100644 --- a/src/Generation/Generator/Renderer/Internal/Parameter/Converter/RecordAsPointerAlias.cs +++ b/src/Generation/Generator/Renderer/Internal/Parameter/Converter/RecordAliasCallback.cs @@ -1,10 +1,10 @@ namespace Generator.Renderer.Internal.Parameter; -internal class RecordAsPointerAlias : ParameterConverter +internal class RecordAliasCallback : ParameterConverter { public bool Supports(GirModel.AnyType anyType) { - return anyType.IsAlias(); + return anyType.IsAlias(out var record) && !Model.Record.IsOpaqueTyped(record); } public RenderableParameter Convert(GirModel.Parameter parameter) diff --git a/src/Generation/Generator/Renderer/Internal/Parameter/Converter/RecordArray.cs b/src/Generation/Generator/Renderer/Internal/Parameter/Converter/RecordArray.cs index ddcc3013c..97cf82f39 100644 --- a/src/Generation/Generator/Renderer/Internal/Parameter/Converter/RecordArray.cs +++ b/src/Generation/Generator/Renderer/Internal/Parameter/Converter/RecordArray.cs @@ -4,7 +4,7 @@ internal class RecordArray : ParameterConverter { public bool Supports(GirModel.AnyType anyType) { - return anyType.IsArray(); + return anyType.IsArray(out var record) && !Model.Record.IsOpaqueTyped(record); } public RenderableParameter Convert(GirModel.Parameter parameter) diff --git a/src/Generation/Generator/Renderer/Internal/Parameter/Converter/RecordAsPointer.cs b/src/Generation/Generator/Renderer/Internal/Parameter/Converter/RecordCallback.cs similarity index 80% rename from src/Generation/Generator/Renderer/Internal/Parameter/Converter/RecordAsPointer.cs rename to src/Generation/Generator/Renderer/Internal/Parameter/Converter/RecordCallback.cs index fcb3f5e7b..cf504768f 100644 --- a/src/Generation/Generator/Renderer/Internal/Parameter/Converter/RecordAsPointer.cs +++ b/src/Generation/Generator/Renderer/Internal/Parameter/Converter/RecordCallback.cs @@ -1,10 +1,10 @@ namespace Generator.Renderer.Internal.Parameter; -internal class RecordAsPointer : ParameterConverter +internal class RecordCallback : ParameterConverter { public bool Supports(GirModel.AnyType anyType) { - return anyType.Is(); + return anyType.Is(out var record) && !Model.Record.IsOpaqueTyped(record); } public RenderableParameter Convert(GirModel.Parameter parameter) diff --git a/src/Generation/Generator/Renderer/Internal/Parameter/Converter/RecordGLibPtrArray.cs b/src/Generation/Generator/Renderer/Internal/Parameter/Converter/RecordGLibPtrArray.cs index a7b2f7180..90c2c1aea 100644 --- a/src/Generation/Generator/Renderer/Internal/Parameter/Converter/RecordGLibPtrArray.cs +++ b/src/Generation/Generator/Renderer/Internal/Parameter/Converter/RecordGLibPtrArray.cs @@ -4,7 +4,7 @@ public class RecordGLibPtrArray : ParameterConverter { public bool Supports(GirModel.AnyType anyType) { - return anyType.IsGLibPtrArray(); + return anyType.IsGLibPtrArray(out var record) && !Model.Record.IsOpaqueTyped(record); } public RenderableParameter Convert(GirModel.Parameter parameter) diff --git a/src/Generation/Generator/Renderer/Internal/Parameter/Parameters.cs b/src/Generation/Generator/Renderer/Internal/Parameter/Parameters.cs index 43b04b861..14cef4f7e 100644 --- a/src/Generation/Generator/Renderer/Internal/Parameter/Parameters.cs +++ b/src/Generation/Generator/Renderer/Internal/Parameter/Parameters.cs @@ -18,6 +18,8 @@ internal static class Parameters new Parameter.Interface(), new Parameter.InterfaceArray(), new Parameter.NativeUnsignedIntegerArray(), + new Parameter.OpaqueTypedRecord(), + new Parameter.OpaqueTypedRecordArray(), new Parameter.Pointer(), new Parameter.PointerAlias(), new Parameter.PointerArray(), diff --git a/src/Generation/Generator/Renderer/Internal/ParameterToManagedExpression/Converter/OpaqueTypedRecord.cs b/src/Generation/Generator/Renderer/Internal/ParameterToManagedExpression/Converter/OpaqueTypedRecord.cs new file mode 100644 index 000000000..6cb874958 --- /dev/null +++ b/src/Generation/Generator/Renderer/Internal/ParameterToManagedExpression/Converter/OpaqueTypedRecord.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; + +namespace Generator.Renderer.Internal.ParameterToManagedExpressions; + +internal class OpaqueTypedRecord : ToManagedParameterConverter +{ + public bool Supports(GirModel.AnyType type) + => type.Is(out var record) && Model.Record.IsOpaqueTyped(record); + + public void Initialize(ParameterToManagedData parameterData, IEnumerable parameters) + { + if (parameterData.Parameter.Direction != GirModel.Direction.In) + throw new NotImplementedException($"{parameterData.Parameter.AnyTypeOrVarArgs}: opaque record with direction != in not yet supported"); + + var record = (GirModel.Record) parameterData.Parameter.AnyTypeOrVarArgs.AsT0.AsT0; + var variableName = Model.Parameter.GetConvertedName(parameterData.Parameter); + + var signatureName = Model.Parameter.GetName(parameterData.Parameter); + + var ownedHandle = parameterData.Parameter switch + { + { Transfer: GirModel.Transfer.Full } => $"new {Model.OpaqueTypedRecord.GetFullyQuallifiedOwnedHandle(record)}({signatureName})", + { Transfer: GirModel.Transfer.None } => $"{Model.OpaqueTypedRecord.GetFullyQuallifiedOwnedHandle(record)}.FromUnowned({signatureName})", + _ => throw new Exception($"Unknown transfer type for opaque typed record parameter {parameterData.Parameter.Name}") + }; + + var nullable = parameterData.Parameter.Nullable + ? $" {signatureName} == IntPtr.Zero ? null :" + : string.Empty; + + parameterData.SetSignatureName(signatureName); + parameterData.SetExpression($"var {variableName} ={nullable} new {Model.OpaqueTypedRecord.GetFullyQualifiedPublicClassName(record)}({ownedHandle});"); + parameterData.SetCallName(variableName); + } +} diff --git a/src/Generation/Generator/Renderer/Internal/ParameterToManagedExpression/Converter/Record.cs b/src/Generation/Generator/Renderer/Internal/ParameterToManagedExpression/Converter/Record.cs index abeac6fe5..17a96e202 100644 --- a/src/Generation/Generator/Renderer/Internal/ParameterToManagedExpression/Converter/Record.cs +++ b/src/Generation/Generator/Renderer/Internal/ParameterToManagedExpression/Converter/Record.cs @@ -6,7 +6,7 @@ namespace Generator.Renderer.Internal.ParameterToManagedExpressions; internal class Record : ToManagedParameterConverter { public bool Supports(GirModel.AnyType type) - => type.Is(); + => type.Is(out var record) && !Model.Record.IsOpaqueTyped(record); public void Initialize(ParameterToManagedData parameterData, IEnumerable parameters) { diff --git a/src/Generation/Generator/Renderer/Internal/ParameterToManagedExpression/Converter/RecordArray.cs b/src/Generation/Generator/Renderer/Internal/ParameterToManagedExpression/Converter/RecordArray.cs index 996115585..06cdb994d 100644 --- a/src/Generation/Generator/Renderer/Internal/ParameterToManagedExpression/Converter/RecordArray.cs +++ b/src/Generation/Generator/Renderer/Internal/ParameterToManagedExpression/Converter/RecordArray.cs @@ -5,7 +5,7 @@ namespace Generator.Renderer.Internal.ParameterToManagedExpressions; internal class RecordArray : ToManagedParameterConverter { public bool Supports(GirModel.AnyType type) - => type.IsArray(); + => type.IsArray(out var record) && !Model.Record.IsOpaqueTyped(record); public void Initialize(ParameterToManagedData parameterData, IEnumerable parameters) { diff --git a/src/Generation/Generator/Renderer/Internal/ParameterToManagedExpression/ParameterToManagedExpression.cs b/src/Generation/Generator/Renderer/Internal/ParameterToManagedExpression/ParameterToManagedExpression.cs index ea56385fc..77958c7ae 100644 --- a/src/Generation/Generator/Renderer/Internal/ParameterToManagedExpression/ParameterToManagedExpression.cs +++ b/src/Generation/Generator/Renderer/Internal/ParameterToManagedExpression/ParameterToManagedExpression.cs @@ -13,6 +13,7 @@ internal static class ParameterToManagedExpression new ParameterToManagedExpressions.Class(), new ParameterToManagedExpressions.Enumeration(), new ParameterToManagedExpressions.Interface(), + new ParameterToManagedExpressions.OpaqueTypedRecord(), new ParameterToManagedExpressions.Pointer(), new ParameterToManagedExpressions.PointerAlias(), new ParameterToManagedExpressions.PrimitiveValueType(), diff --git a/src/Generation/Generator/Renderer/Internal/ReturnType/Converter/OpaqueTypedRecord.cs b/src/Generation/Generator/Renderer/Internal/ReturnType/Converter/OpaqueTypedRecord.cs new file mode 100644 index 000000000..c61145d6c --- /dev/null +++ b/src/Generation/Generator/Renderer/Internal/ReturnType/Converter/OpaqueTypedRecord.cs @@ -0,0 +1,25 @@ +using GirModel; + +namespace Generator.Renderer.Internal.ReturnType; + +internal class OpaqueTypedRecord : ReturnTypeConverter +{ + public bool Supports(GirModel.ReturnType returnType) + { + return returnType.AnyType.Is(out var record) && Model.Record.IsOpaqueTyped(record); + } + + public RenderableReturnType Convert(GirModel.ReturnType returnType) + { + var type = (GirModel.Record) returnType.AnyType.AsT0; + + var typeName = returnType switch + { + { Transfer: Transfer.Full } => Model.OpaqueTypedRecord.GetFullyQuallifiedOwnedHandle(type), + _ => Model.OpaqueTypedRecord.GetFullyQuallifiedUnownedHandle(type) + }; + + //Returned SafeHandles are never "null" but "invalid" in case of C NULL. + return new RenderableReturnType(typeName); + } +} diff --git a/src/Generation/Generator/Renderer/Internal/ReturnType/Converter/OpaqueTypedRecordCallback.cs b/src/Generation/Generator/Renderer/Internal/ReturnType/Converter/OpaqueTypedRecordCallback.cs new file mode 100644 index 000000000..aa74b1da0 --- /dev/null +++ b/src/Generation/Generator/Renderer/Internal/ReturnType/Converter/OpaqueTypedRecordCallback.cs @@ -0,0 +1,14 @@ +namespace Generator.Renderer.Internal.ReturnType; + +internal class OpaqueTypedRecordCallback : ReturnTypeConverter +{ + public bool Supports(GirModel.ReturnType returnType) + { + return returnType.AnyType.Is(out var record) && Model.Record.IsOpaqueTyped(record); + } + + public RenderableReturnType Convert(GirModel.ReturnType returnType) + { + return new RenderableReturnType(Model.Type.Pointer); + } +} diff --git a/src/Generation/Generator/Renderer/Internal/ReturnType/Converter/Record.cs b/src/Generation/Generator/Renderer/Internal/ReturnType/Converter/Record.cs index 1ed8d0f87..8c35e4ba2 100644 --- a/src/Generation/Generator/Renderer/Internal/ReturnType/Converter/Record.cs +++ b/src/Generation/Generator/Renderer/Internal/ReturnType/Converter/Record.cs @@ -4,7 +4,7 @@ internal class Record : ReturnTypeConverter { public bool Supports(GirModel.ReturnType returnType) { - return returnType.AnyType.Is(); + return returnType.AnyType.Is(out var record) && !Model.Record.IsOpaqueTyped(record); } public RenderableReturnType Convert(GirModel.ReturnType returnType) diff --git a/src/Generation/Generator/Renderer/Internal/ReturnType/Converter/RecordArray.cs b/src/Generation/Generator/Renderer/Internal/ReturnType/Converter/RecordArray.cs index 0ba902075..035d9403b 100644 --- a/src/Generation/Generator/Renderer/Internal/ReturnType/Converter/RecordArray.cs +++ b/src/Generation/Generator/Renderer/Internal/ReturnType/Converter/RecordArray.cs @@ -6,7 +6,7 @@ internal class RecordArray : ReturnTypeConverter { public bool Supports(GirModel.ReturnType returnType) { - return returnType.AnyType.IsArray(); + return returnType.AnyType.IsArray(out var record) && !Model.Record.IsOpaqueTyped(record); } public RenderableReturnType Convert(GirModel.ReturnType returnType) diff --git a/src/Generation/Generator/Renderer/Internal/ReturnType/Converter/RecordInCallback.cs b/src/Generation/Generator/Renderer/Internal/ReturnType/Converter/RecordInCallback.cs index c52e7c556..fb1191d95 100644 --- a/src/Generation/Generator/Renderer/Internal/ReturnType/Converter/RecordInCallback.cs +++ b/src/Generation/Generator/Renderer/Internal/ReturnType/Converter/RecordInCallback.cs @@ -4,7 +4,7 @@ internal class RecordInCallback : ReturnTypeConverter { public bool Supports(GirModel.ReturnType returnType) { - return returnType.AnyType.Is(); + return returnType.AnyType.Is(out var record) && !Model.Record.IsOpaqueTyped(record); } public RenderableReturnType Convert(GirModel.ReturnType returnType) diff --git a/src/Generation/Generator/Renderer/Internal/ReturnType/ReturnTypeRenderer.cs b/src/Generation/Generator/Renderer/Internal/ReturnType/ReturnTypeRenderer.cs index 9cf316808..42644a44a 100644 --- a/src/Generation/Generator/Renderer/Internal/ReturnType/ReturnTypeRenderer.cs +++ b/src/Generation/Generator/Renderer/Internal/ReturnType/ReturnTypeRenderer.cs @@ -12,6 +12,7 @@ internal static class ReturnTypeRenderer new ReturnType.Enumeration(), new ReturnType.Interface(), new ReturnType.InterfaceGLibPtrArray(), + new ReturnType.OpaqueTypedRecord(), new ReturnType.PlatformString(), new ReturnType.Pointer(), new ReturnType.PointerAlias(), diff --git a/src/Generation/Generator/Renderer/Internal/ReturnType/ReturnTypeRendererCallback.cs b/src/Generation/Generator/Renderer/Internal/ReturnType/ReturnTypeRendererCallback.cs index fb98eb764..dd6e2083a 100644 --- a/src/Generation/Generator/Renderer/Internal/ReturnType/ReturnTypeRendererCallback.cs +++ b/src/Generation/Generator/Renderer/Internal/ReturnType/ReturnTypeRendererCallback.cs @@ -12,6 +12,7 @@ internal static class ReturnTypeRendererCallback new ReturnType.Enumeration(), new ReturnType.Interface(), new ReturnType.InterfaceGLibPtrArray(), + new ReturnType.OpaqueTypedRecordCallback(), new ReturnType.PlatformStringInCallback(), new ReturnType.Pointer(), new ReturnType.PrimitiveValueType(), diff --git a/src/Generation/Generator/Renderer/Internal/ReturnTypeToNativeExpression/Converter/OpaqueTypedRecord.cs b/src/Generation/Generator/Renderer/Internal/ReturnTypeToNativeExpression/Converter/OpaqueTypedRecord.cs new file mode 100644 index 000000000..d1992e25a --- /dev/null +++ b/src/Generation/Generator/Renderer/Internal/ReturnTypeToNativeExpression/Converter/OpaqueTypedRecord.cs @@ -0,0 +1,21 @@ +using System; + +namespace Generator.Renderer.Internal.ReturnTypeToNativeExpressions; + +internal class OpaqueTypedRecord : ReturnTypeConverter +{ + public bool Supports(GirModel.AnyType type) + => type.Is(out var record) && Model.Record.IsOpaqueTyped(record); + + public string GetString(GirModel.ReturnType returnType, string fromVariableName) + { + return returnType switch + { + { Transfer: GirModel.Transfer.None, Nullable: true } => $"{fromVariableName}?.Handle.DangerousGetHandle() ?? IntPtr.Zero", + { Transfer: GirModel.Transfer.None, Nullable: false } => $"{fromVariableName}.Handle.DangerousGetHandle()", + { Transfer: GirModel.Transfer.Full, Nullable: true } => $"{fromVariableName}?.Handle.UnownedCopy().DangerousGetHandle() ?? IntPtr.Zero", + { Transfer: GirModel.Transfer.Full, Nullable: false } => $"{fromVariableName}.Handle.UnownedCopy().DangerousGetHandle()", + _ => throw new Exception($"Unknown transfer type for opaque record return type which should be converted to native.") + }; + } +} diff --git a/src/Generation/Generator/Renderer/Internal/ReturnTypeToNativeExpression/Converter/Record.cs b/src/Generation/Generator/Renderer/Internal/ReturnTypeToNativeExpression/Converter/Record.cs index c99ad4845..cf3d7415f 100644 --- a/src/Generation/Generator/Renderer/Internal/ReturnTypeToNativeExpression/Converter/Record.cs +++ b/src/Generation/Generator/Renderer/Internal/ReturnTypeToNativeExpression/Converter/Record.cs @@ -5,7 +5,7 @@ namespace Generator.Renderer.Internal.ReturnTypeToNativeExpressions; internal class Record : ReturnTypeConverter { public bool Supports(AnyType type) - => type.Is(); + => type.Is(out var record) && !Model.Record.IsOpaqueTyped(record); public string GetString(GirModel.ReturnType returnType, string fromVariableName) => fromVariableName + ".Handle"; diff --git a/src/Generation/Generator/Renderer/Internal/ReturnTypeToNativeExpression/ReturnTypeToNativeExpression.cs b/src/Generation/Generator/Renderer/Internal/ReturnTypeToNativeExpression/ReturnTypeToNativeExpression.cs index db050aa1f..a0f5c3e67 100644 --- a/src/Generation/Generator/Renderer/Internal/ReturnTypeToNativeExpression/ReturnTypeToNativeExpression.cs +++ b/src/Generation/Generator/Renderer/Internal/ReturnTypeToNativeExpression/ReturnTypeToNativeExpression.cs @@ -10,6 +10,7 @@ internal static class ReturnTypeToNativeExpression new ReturnTypeToNativeExpressions.Class(), new ReturnTypeToNativeExpressions.Enumeration(), new ReturnTypeToNativeExpressions.Interface(), + new ReturnTypeToNativeExpressions.OpaqueTypedRecord(), new ReturnTypeToNativeExpressions.Pointer(), new ReturnTypeToNativeExpressions.PrimitiveValueType(), new ReturnTypeToNativeExpressions.PrimitiveValueTypeAlias(), diff --git a/src/Generation/Generator/Renderer/Public/Constructor/ConstructorData.cs b/src/Generation/Generator/Renderer/Public/Constructor/ConstructorData.cs index 3beed61e4..7fbc63cc9 100644 --- a/src/Generation/Generator/Renderer/Public/Constructor/ConstructorData.cs +++ b/src/Generation/Generator/Renderer/Public/Constructor/ConstructorData.cs @@ -2,4 +2,4 @@ public delegate string CreateExpression(GirModel.Constructor constructor, string fromVariableName); -public record ConstructorData(bool RequiresNewModifier, CreateExpression GetCreateExpression); +public record ConstructorData(bool RequiresNewModifier, CreateExpression GetCreateExpression, bool AllowRendering); diff --git a/src/Generation/Generator/Renderer/Public/Constructor/ConstructorRenderer.cs b/src/Generation/Generator/Renderer/Public/Constructor/ConstructorRenderer.cs index e50b87c3e..6a4429666 100644 --- a/src/Generation/Generator/Renderer/Public/Constructor/ConstructorRenderer.cs +++ b/src/Generation/Generator/Renderer/Public/Constructor/ConstructorRenderer.cs @@ -10,6 +10,7 @@ internal static class ConstructorRenderer private static readonly List Converters = new() { new Constructor.Class(), + new Constructor.OpaqueTypedRecord(), }; public static string Render(GirModel.Constructor constructor) @@ -17,6 +18,10 @@ public static string Render(GirModel.Constructor constructor) try { var constructorData = GetData(constructor); + + if (!constructorData.AllowRendering) + return string.Empty; + var parameters = ParameterToNativeExpression.Initialize(constructor.Parameters); var newKeyWord = constructorData.RequiresNewModifier @@ -25,7 +30,7 @@ public static string Render(GirModel.Constructor constructor) return @$" {VersionAttribute.Render(constructor.Version)} -public static {newKeyWord}{constructor.Parent.Name} {Model.Constructor.GetName(constructor)}({RenderParameters(parameters)}) +public static {newKeyWord}{constructor.Parent.Name}{Nullable.Render(constructor.ReturnType)} {Model.Constructor.GetName(constructor)}({RenderParameters(parameters)}) {{ {RenderContent(parameters)} {RenderCallStatement(constructor, parameters, constructorData)} diff --git a/src/Generation/Generator/Renderer/Public/Constructor/Converter/Class.cs b/src/Generation/Generator/Renderer/Public/Constructor/Converter/Class.cs index 41cee828a..dc190c18d 100644 --- a/src/Generation/Generator/Renderer/Public/Constructor/Converter/Class.cs +++ b/src/Generation/Generator/Renderer/Public/Constructor/Converter/Class.cs @@ -12,7 +12,8 @@ public ConstructorData GetData(GirModel.Constructor constructor) var parentClass = ((GirModel.Class) constructor.Parent).Parent; return new( RequiresNewModifier: Model.Class.HidesConstructor(parentClass, constructor), - GetCreateExpression: CreateExpression + GetCreateExpression: CreateExpression, + AllowRendering: true ); } diff --git a/src/Generation/Generator/Renderer/Public/Constructor/Converter/OpaqueTypedRecord.cs b/src/Generation/Generator/Renderer/Public/Constructor/Converter/OpaqueTypedRecord.cs new file mode 100644 index 000000000..d6312fb28 --- /dev/null +++ b/src/Generation/Generator/Renderer/Public/Constructor/Converter/OpaqueTypedRecord.cs @@ -0,0 +1,32 @@ +namespace Generator.Renderer.Public.Constructor; + +public class OpaqueTypedRecord : ConstructorConverter +{ + public bool Supports(GirModel.Constructor constructor) + { + return constructor.Parent is GirModel.Record record && Model.Record.IsOpaqueTyped(record); + } + + public ConstructorData GetData(GirModel.Constructor constructor) + { + return new( + RequiresNewModifier: false, + GetCreateExpression: CreateExpression, + + //Constructors which do not transfer ownership likely create floating references. + //as there is no way to know how to sink those references those constructors are not rendered + //automatically as part of the public api and must be implemented manually. + AllowRendering: constructor.ReturnType.Transfer == GirModel.Transfer.Full + ); + } + + private static string CreateExpression(GirModel.Constructor constructor, string fromVariableName) + { + var record = (GirModel.Record) constructor.Parent; + var createInstance = $"new {record.Name}({fromVariableName})"; + + return constructor.ReturnType.Nullable + ? $"{fromVariableName}.IsInvalid ? null : {createInstance}" + : createInstance; + } +} diff --git a/src/Generation/Generator/Renderer/Public/FunctionRenderer.cs b/src/Generation/Generator/Renderer/Public/FunctionRenderer.cs index cd1ee987e..3e89e955b 100644 --- a/src/Generation/Generator/Renderer/Public/FunctionRenderer.cs +++ b/src/Generation/Generator/Renderer/Public/FunctionRenderer.cs @@ -8,10 +8,14 @@ namespace Generator.Renderer.Public; internal static class FunctionRenderer { - public static string Render(GirModel.Function function) + public static string Render(GirModel.Function? function) { + if (function is null) + return string.Empty; + if (!IsSupported(function)) return string.Empty; + try { var parameters = ParameterToNativeExpression.Initialize(function.Parameters); diff --git a/src/Generation/Generator/Renderer/Public/InstanceParameterToNativeExpression/Converter/OpaqueTypedRecord.cs b/src/Generation/Generator/Renderer/Public/InstanceParameterToNativeExpression/Converter/OpaqueTypedRecord.cs new file mode 100644 index 000000000..226649dcd --- /dev/null +++ b/src/Generation/Generator/Renderer/Public/InstanceParameterToNativeExpression/Converter/OpaqueTypedRecord.cs @@ -0,0 +1,21 @@ +using System; + +namespace Generator.Renderer.Public.InstanceParameterToNativeExpressions; + +public class OpaqueTypedRecord : InstanceParameterConverter +{ + public bool Supports(GirModel.Type type) + { + return type is GirModel.Record record && Model.Record.IsOpaqueTyped(record); + } + + public string GetExpression(GirModel.InstanceParameter instanceParameter) + { + return instanceParameter switch + { + { Transfer: GirModel.Transfer.None } => "this.Handle", + { Transfer: GirModel.Transfer.Full } => "this.Handle.UnownedCopy()", + _ => throw new Exception("Unknown transfer type for instance parameter converter") + }; + } +} diff --git a/src/Generation/Generator/Renderer/Public/InstanceParameterToNativeExpression/InstanceParameterToNativeExpression.cs b/src/Generation/Generator/Renderer/Public/InstanceParameterToNativeExpression/InstanceParameterToNativeExpression.cs index de205060a..1bccb47f3 100644 --- a/src/Generation/Generator/Renderer/Public/InstanceParameterToNativeExpression/InstanceParameterToNativeExpression.cs +++ b/src/Generation/Generator/Renderer/Public/InstanceParameterToNativeExpression/InstanceParameterToNativeExpression.cs @@ -8,6 +8,7 @@ internal static class InstanceParameterToNativeExpression { new InstanceParameterToNativeExpressions.Class(), new InstanceParameterToNativeExpressions.Interface(), + new InstanceParameterToNativeExpressions.OpaqueTypedRecord(), new InstanceParameterToNativeExpressions.Pointer(), }; diff --git a/src/Generation/Generator/Renderer/Public/OpaqueTypedRecord.cs b/src/Generation/Generator/Renderer/Public/OpaqueTypedRecord.cs new file mode 100644 index 000000000..b405ba7f6 --- /dev/null +++ b/src/Generation/Generator/Renderer/Public/OpaqueTypedRecord.cs @@ -0,0 +1,56 @@ +using System; +using System.Linq; +using Generator.Model; + +namespace Generator.Renderer.Public; + +internal static class OpaqueTypedRecord +{ + public static string Render(GirModel.Record record) + { + var name = Model.OpaqueTypedRecord.GetPublicClassName(record); + var internalHandleName = Model.OpaqueTypedRecord.GetFullyQuallifiedOwnedHandle(record); + + return $@" +using System; +using System.Linq; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; + +#nullable enable + +namespace {Namespace.GetPublicName(record.Namespace)}; + +// AUTOGENERATED FILE - DO NOT MODIFY + +{PlatformSupportAttribute.Render(record as GirModel.PlatformDependent)} +public partial class {name} +{{ + public {internalHandleName} Handle {{ get; }} + + public {name}({internalHandleName} handle) + {{ + Handle = handle; + Initialize(); + }} + + // Implement this to perform additional steps in the constructor + partial void Initialize(); + + {record.Constructors + .Select(ConstructorRenderer.Render) + .Join(Environment.NewLine)} + + {FunctionRenderer.Render(record.TypeFunction)} + + {record.Functions + .Select(FunctionRenderer.Render) + .Join(Environment.NewLine)} + + {record.Methods + .Where(Method.IsEnabled) + .Select(MethodRenderer.Render) + .Join(Environment.NewLine)} +}}"; + } +} diff --git a/src/Generation/Generator/Renderer/Public/Parameter/Converter/OpaqueTypedRecord.cs b/src/Generation/Generator/Renderer/Public/Parameter/Converter/OpaqueTypedRecord.cs new file mode 100644 index 000000000..c7c023a41 --- /dev/null +++ b/src/Generation/Generator/Renderer/Public/Parameter/Converter/OpaqueTypedRecord.cs @@ -0,0 +1,31 @@ +using System; + +namespace Generator.Renderer.Public.Parameter; + +internal class OpaqueTypedRecord : ParameterConverter +{ + public bool Supports(GirModel.AnyType anyType) + { + return anyType.Is(out var record) && Model.Record.IsOpaqueTyped(record); + } + + public ParameterTypeData Create(GirModel.Parameter parameter) + { + return new ParameterTypeData( + Direction: GetDirection(parameter), + NullableTypeName: GetNullableTypeName(parameter) + ); + } + + private static string GetNullableTypeName(GirModel.Parameter parameter) + { + var type = (GirModel.Record) parameter.AnyTypeOrVarArgs.AsT0.AsT0; + return Model.OpaqueTypedRecord.GetFullyQualifiedPublicClassName(type) + Nullable.Render(parameter); + } + + private static string GetDirection(GirModel.Parameter parameter) => parameter switch + { + { Direction: GirModel.Direction.In } => ParameterDirection.In(), + _ => throw new Exception("Opaque records with direction != in not yet supported") + }; +} diff --git a/src/Generation/Generator/Renderer/Public/Parameter/Converter/OpaqueTypedRecordArray.cs b/src/Generation/Generator/Renderer/Public/Parameter/Converter/OpaqueTypedRecordArray.cs new file mode 100644 index 000000000..ed817d932 --- /dev/null +++ b/src/Generation/Generator/Renderer/Public/Parameter/Converter/OpaqueTypedRecordArray.cs @@ -0,0 +1,31 @@ +using System; + +namespace Generator.Renderer.Public.Parameter; + +internal class OpaqueTypedRecordArray : ParameterConverter +{ + public bool Supports(GirModel.AnyType anyType) + { + return anyType.IsArray(out var record) && Model.Record.IsOpaqueTyped(record); + } + + public ParameterTypeData Create(GirModel.Parameter parameter) + { + return new ParameterTypeData( + Direction: GetDirection(parameter), + NullableTypeName: GetNullableTypeName(parameter) + ); + } + + private static string GetNullableTypeName(GirModel.Parameter parameter) + { + var arrayType = parameter.AnyTypeOrVarArgs.AsT0.AsT1; + return $"{Model.OpaqueTypedRecord.GetFullyQualifiedPublicClassName((GirModel.Record) arrayType.AnyType.AsT0)}[]{Nullable.Render(parameter)}"; + } + + private static string GetDirection(GirModel.Parameter parameter) => parameter switch + { + { Direction: GirModel.Direction.In } => ParameterDirection.In(), + _ => throw new Exception($"Unknown direction for opaque typed record in parameter {parameter.Name}.") + }; +} diff --git a/src/Generation/Generator/Renderer/Public/Parameter/Converter/Record.cs b/src/Generation/Generator/Renderer/Public/Parameter/Converter/Record.cs index 01c0c5a41..f7b275348 100644 --- a/src/Generation/Generator/Renderer/Public/Parameter/Converter/Record.cs +++ b/src/Generation/Generator/Renderer/Public/Parameter/Converter/Record.cs @@ -4,7 +4,7 @@ internal class Record : ParameterConverter { public bool Supports(GirModel.AnyType anyType) { - return anyType.Is(); + return anyType.Is(out var record) && !Model.Record.IsOpaqueTyped(record); } public ParameterTypeData Create(GirModel.Parameter parameter) diff --git a/src/Generation/Generator/Renderer/Public/Parameter/Converter/RecordArray.cs b/src/Generation/Generator/Renderer/Public/Parameter/Converter/RecordArray.cs index 726e4c702..8cfa32977 100644 --- a/src/Generation/Generator/Renderer/Public/Parameter/Converter/RecordArray.cs +++ b/src/Generation/Generator/Renderer/Public/Parameter/Converter/RecordArray.cs @@ -4,7 +4,7 @@ internal class RecordArray : ParameterConverter { public bool Supports(GirModel.AnyType anyType) { - return anyType.IsArray(); + return anyType.IsArray(out var record) && !Model.Record.IsOpaqueTyped(record); } public ParameterTypeData Create(GirModel.Parameter parameter) diff --git a/src/Generation/Generator/Renderer/Public/Parameter/ParameterRenderer.cs b/src/Generation/Generator/Renderer/Public/Parameter/ParameterRenderer.cs index 9e814337d..6d1cce19a 100644 --- a/src/Generation/Generator/Renderer/Public/Parameter/ParameterRenderer.cs +++ b/src/Generation/Generator/Renderer/Public/Parameter/ParameterRenderer.cs @@ -13,6 +13,8 @@ internal static class ParameterRenderer new Parameter.Enumeration(), new Parameter.Interface(), new Parameter.InterfaceArray(), + new Parameter.OpaqueTypedRecord(), + new Parameter.OpaqueTypedRecordArray(), new Parameter.Pointer(), new Parameter.PointerAlias(), new Parameter.PrimitiveValueType(), diff --git a/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/OpaqueTypedRecord.cs b/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/OpaqueTypedRecord.cs new file mode 100644 index 000000000..ec1185306 --- /dev/null +++ b/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/OpaqueTypedRecord.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; + +namespace Generator.Renderer.Public.ParameterToNativeExpressions; + +internal class OpaqueTypedRecord : ToNativeParameterConverter +{ + public bool Supports(GirModel.AnyType type) + => type.Is(out var record) && Model.Record.IsOpaqueTyped(record); + + public void Initialize(ParameterToNativeData parameter, IEnumerable _) + { + if (parameter.Parameter.Direction != GirModel.Direction.In) + throw new NotImplementedException($"{parameter.Parameter.AnyTypeOrVarArgs}: opaque record parameter '{parameter.Parameter.Name}' with direction != in not yet supported"); + + var record = (GirModel.Record) parameter.Parameter.AnyTypeOrVarArgs.AsT0.AsT0; + var typeHandle = Model.OpaqueTypedRecord.GetFullyQuallifiedInternalHandle(record); + var nullHandle = Model.OpaqueTypedRecord.GetFullyQuallifiedNullHandle(record); + var signatureName = Model.Parameter.GetName(parameter.Parameter); + + var callName = parameter.Parameter switch + { + { Nullable: true, Transfer: GirModel.Transfer.None } => $"({typeHandle}?) {signatureName}?.Handle ?? {nullHandle}", + { Nullable: false, Transfer: GirModel.Transfer.None } => $"{signatureName}.Handle", + { Nullable: true, Transfer: GirModel.Transfer.Full } => $"{signatureName}?.Handle.UnownedCopy() ?? {nullHandle}", + { Nullable: false, Transfer: GirModel.Transfer.Full } => $"{signatureName}.Handle.UnownedCopy()", + _ => throw new Exception($"Can't detect call name for parameter opaque parameter {parameter.Parameter.Name}") + }; + + parameter.SetSignatureName(signatureName); + parameter.SetCallName(callName); + } +} diff --git a/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/OpaqueTypedRecordArray.cs b/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/OpaqueTypedRecordArray.cs new file mode 100644 index 000000000..02ddf7d32 --- /dev/null +++ b/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/OpaqueTypedRecordArray.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Generator.Renderer.Public.ParameterToNativeExpressions; + +internal class OpaqueTypedRecordArray : ToNativeParameterConverter +{ + public bool Supports(GirModel.AnyType type) + => type.IsArray(out var record) && Model.Record.IsOpaqueTyped(record); + + public void Initialize(ParameterToNativeData parameterData, IEnumerable parameters) + { + switch (parameterData.Parameter) + { + case { Direction: GirModel.Direction.In } + when parameterData.Parameter.AnyTypeOrVarArgs.AsT0.AsT1.Length is not null: + Span(parameterData, parameters); + break; + case { Direction: GirModel.Direction.In }: + Ref(parameterData); + break; + default: + throw new Exception($"{parameterData.Parameter}: This kind of opaque typed array is not yet supported"); + } + } + + private static void Ref(ParameterToNativeData parameter) + { + var parameterName = Model.Parameter.GetName(parameter.Parameter); + parameter.SetSignatureName(parameterName); + parameter.SetCallName($"ref {parameterName}"); + + //TODO + throw new Exception("Test missing for opaque typed record array passed in via a ref"); + } + + private static void Span(ParameterToNativeData parameter, IEnumerable allParameters) + { + var parameterName = Model.Parameter.GetName(parameter.Parameter); + var nativeVariableName = parameterName + "Native"; + + parameter.SetSignatureName(parameterName); + parameter.SetCallName($"ref MemoryMarshal.GetReference({nativeVariableName})"); + + var nullable = parameter.Parameter.Nullable + ? $"{parameterName} is null ? null : " + : string.Empty; + + parameter.SetExpression($"var {nativeVariableName} = new Span({nullable}{parameterName}" + + $".Select(record => record.Handle.DangerousGetHandle()).ToArray());"); + + var lengthIndex = parameter.Parameter.AnyTypeOrVarArgs.AsT0.AsT1.Length ?? throw new Exception("Length missing"); + var lengthParameter = allParameters.ElementAt(lengthIndex); + var lengthParameterType = Model.Type.GetName(lengthParameter.Parameter.AnyTypeOrVarArgs.AsT0.AsT0); + + switch (lengthParameter.Parameter.Direction) + { + case GirModel.Direction.In: + lengthParameter.IsArrayLengthParameter = true; + lengthParameter.SetCallName(parameter.Parameter.Nullable + ? $"({lengthParameterType}) ({parameterName}?.Length ?? 0)" + : $"({lengthParameterType}) {parameterName}.Length" + ); + break; + default: + throw new Exception("Unknown direction for length parameter in opaque typed record array"); + } + } +} diff --git a/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/Record.cs b/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/Record.cs index 5baba2ef1..2aaabd4a3 100644 --- a/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/Record.cs +++ b/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/Record.cs @@ -7,7 +7,7 @@ namespace Generator.Renderer.Public.ParameterToNativeExpressions; internal class Record : ToNativeParameterConverter { public bool Supports(GirModel.AnyType type) - => type.Is(); + => type.Is(out var record) && !Model.Record.IsOpaqueTyped(record); public void Initialize(ParameterToNativeData parameter, IEnumerable _) { diff --git a/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/RecordArray.cs b/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/RecordArray.cs index dc2330bc9..04bc6082f 100644 --- a/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/RecordArray.cs +++ b/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/RecordArray.cs @@ -8,7 +8,7 @@ namespace Generator.Renderer.Public.ParameterToNativeExpressions; internal class RecordArray : ToNativeParameterConverter { public bool Supports(GirModel.AnyType type) - => type.IsArray(); + => type.IsArray(out var record) && !Model.Record.IsOpaqueTyped(record); public void Initialize(ParameterToNativeData parameter, IEnumerable _) { diff --git a/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/ParameterToNativeExpression.cs b/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/ParameterToNativeExpression.cs index f56fa261c..02a845ae8 100644 --- a/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/ParameterToNativeExpression.cs +++ b/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/ParameterToNativeExpression.cs @@ -15,6 +15,8 @@ internal static class ParameterToNativeExpression new ParameterToNativeExpressions.Enumeration(), new ParameterToNativeExpressions.Interface(), new ParameterToNativeExpressions.InterfaceArray(), + new ParameterToNativeExpressions.OpaqueTypedRecord(), + new ParameterToNativeExpressions.OpaqueTypedRecordArray(), new ParameterToNativeExpressions.PlatformString(), new ParameterToNativeExpressions.Pointer(), new ParameterToNativeExpressions.PointerAlias(), diff --git a/src/Generation/Generator/Renderer/Public/ReturnType/Converter/OpaqueTypedRecord.cs b/src/Generation/Generator/Renderer/Public/ReturnType/Converter/OpaqueTypedRecord.cs new file mode 100644 index 000000000..58aff3764 --- /dev/null +++ b/src/Generation/Generator/Renderer/Public/ReturnType/Converter/OpaqueTypedRecord.cs @@ -0,0 +1,16 @@ +using Generator.Model; + +namespace Generator.Renderer.Public.ReturnType; + +internal class OpaqueTypedRecord : ReturnTypeConverter +{ + public RenderableReturnType Create(GirModel.ReturnType returnType) + { + var typeName = ComplexType.GetFullyQualified((GirModel.Record) returnType.AnyType.AsT0); + + return new RenderableReturnType(typeName + Nullable.Render(returnType)); + } + + public bool Supports(GirModel.ReturnType returnType) + => returnType.AnyType.Is(out var record) && Model.Record.IsOpaqueTyped(record); +} diff --git a/src/Generation/Generator/Renderer/Public/ReturnType/Converter/Record.cs b/src/Generation/Generator/Renderer/Public/ReturnType/Converter/Record.cs index 95d4b22ea..6ea554096 100644 --- a/src/Generation/Generator/Renderer/Public/ReturnType/Converter/Record.cs +++ b/src/Generation/Generator/Renderer/Public/ReturnType/Converter/Record.cs @@ -12,5 +12,5 @@ public RenderableReturnType Create(GirModel.ReturnType returnType) } public bool Supports(GirModel.ReturnType returnType) - => returnType.AnyType.Is(); + => returnType.AnyType.Is(out var record) && !Model.Record.IsOpaqueTyped(record); } diff --git a/src/Generation/Generator/Renderer/Public/ReturnType/Converter/RecordArray.cs b/src/Generation/Generator/Renderer/Public/ReturnType/Converter/RecordArray.cs index 5c8b68f0c..0178d39f9 100644 --- a/src/Generation/Generator/Renderer/Public/ReturnType/Converter/RecordArray.cs +++ b/src/Generation/Generator/Renderer/Public/ReturnType/Converter/RecordArray.cs @@ -10,5 +10,5 @@ public RenderableReturnType Create(GirModel.ReturnType returnType) } public bool Supports(GirModel.ReturnType returnType) - => returnType.AnyType.IsArray(); + => returnType.AnyType.IsArray(out var record) && !Model.Record.IsOpaqueTyped(record); } diff --git a/src/Generation/Generator/Renderer/Public/ReturnType/ReturnTypeRenderer.cs b/src/Generation/Generator/Renderer/Public/ReturnType/ReturnTypeRenderer.cs index 6107f1e9a..5978618ff 100644 --- a/src/Generation/Generator/Renderer/Public/ReturnType/ReturnTypeRenderer.cs +++ b/src/Generation/Generator/Renderer/Public/ReturnType/ReturnTypeRenderer.cs @@ -10,6 +10,7 @@ internal static class ReturnTypeRenderer new ReturnType.Class(), new ReturnType.Enumeration(), new ReturnType.Interface(), + new ReturnType.OpaqueTypedRecord(), new ReturnType.Pointer(), new ReturnType.PointerAlias(), new ReturnType.PrimitiveValueType(), diff --git a/src/Generation/Generator/Renderer/Public/ReturnType/ReturnTypeRendererCallback.cs b/src/Generation/Generator/Renderer/Public/ReturnType/ReturnTypeRendererCallback.cs index 44b6a2de4..af9faccd9 100644 --- a/src/Generation/Generator/Renderer/Public/ReturnType/ReturnTypeRendererCallback.cs +++ b/src/Generation/Generator/Renderer/Public/ReturnType/ReturnTypeRendererCallback.cs @@ -10,6 +10,7 @@ internal static class ReturnTypeRendererCallback new ReturnType.Class(), new ReturnType.Enumeration(), new ReturnType.Interface(), + new ReturnType.OpaqueTypedRecord(), new ReturnType.Pointer(), new ReturnType.PointerAlias(), new ReturnType.PrimitiveValueType(), diff --git a/src/Generation/Generator/Renderer/Public/ReturnTypeToManagedExpression/Converter/OpaqueTypedRecord.cs b/src/Generation/Generator/Renderer/Public/ReturnTypeToManagedExpression/Converter/OpaqueTypedRecord.cs new file mode 100644 index 000000000..c85ec4095 --- /dev/null +++ b/src/Generation/Generator/Renderer/Public/ReturnTypeToManagedExpression/Converter/OpaqueTypedRecord.cs @@ -0,0 +1,28 @@ +using System; +using GirModel; + +namespace Generator.Renderer.Public.ReturnTypeToManagedExpressions; + +internal class OpaqueTypedRecord : ReturnTypeConverter +{ + public bool Supports(AnyType type) + => type.Is(out var record) && Model.Record.IsOpaqueTyped(record); + + public string GetString(GirModel.ReturnType returnType, string fromVariableName) + { + var record = (GirModel.Record) returnType.AnyType.AsT0; + + var handleExpression = returnType switch + { + { Transfer: Transfer.Full } => fromVariableName, + { Transfer: Transfer.None } => $"{fromVariableName}.OwnedCopy()", + _ => throw new NotImplementedException("Unknown transfer type") + }; + + var createNewInstance = $"new {Model.ComplexType.GetFullyQualified(record)}({handleExpression})"; + + return returnType.Nullable + ? $"{fromVariableName}.IsInvalid ? null : {createNewInstance};" + : createNewInstance; + } +} diff --git a/src/Generation/Generator/Renderer/Public/ReturnTypeToManagedExpression/Converter/Record.cs b/src/Generation/Generator/Renderer/Public/ReturnTypeToManagedExpression/Converter/Record.cs index 6b7dbc858..59d1bb049 100644 --- a/src/Generation/Generator/Renderer/Public/ReturnTypeToManagedExpression/Converter/Record.cs +++ b/src/Generation/Generator/Renderer/Public/ReturnTypeToManagedExpression/Converter/Record.cs @@ -6,7 +6,7 @@ namespace Generator.Renderer.Public.ReturnTypeToManagedExpressions; internal class Record : ReturnTypeConverter { public bool Supports(AnyType type) - => type.Is(); + => type.Is(out var record) && !Model.Record.IsOpaqueTyped(record); public string GetString(GirModel.ReturnType returnType, string fromVariableName) { diff --git a/src/Generation/Generator/Renderer/Public/ReturnTypeToManagedExpression/ReturnTypeToManagedExpression.cs b/src/Generation/Generator/Renderer/Public/ReturnTypeToManagedExpression/ReturnTypeToManagedExpression.cs index 7e5162c0c..6422df0e9 100644 --- a/src/Generation/Generator/Renderer/Public/ReturnTypeToManagedExpression/ReturnTypeToManagedExpression.cs +++ b/src/Generation/Generator/Renderer/Public/ReturnTypeToManagedExpression/ReturnTypeToManagedExpression.cs @@ -10,6 +10,7 @@ internal static class ReturnTypeToManagedExpression new ReturnTypeToManagedExpressions.Class(), new ReturnTypeToManagedExpressions.Enumeration(), new ReturnTypeToManagedExpressions.Interface(), + new ReturnTypeToManagedExpressions.OpaqueTypedRecord(), new ReturnTypeToManagedExpressions.PlatformString(), new ReturnTypeToManagedExpressions.Pointer(), new ReturnTypeToManagedExpressions.PointerAlias(), diff --git a/src/Generation/GirModel/AnyType.cs b/src/Generation/GirModel/AnyType.cs index 90065ded9..8bb503c4c 100644 --- a/src/Generation/GirModel/AnyType.cs +++ b/src/Generation/GirModel/AnyType.cs @@ -1,15 +1,35 @@ -using OneOf; +using System.Diagnostics.CodeAnalysis; +using OneOf; public static class AnyTypeExtension { public static bool Is(this GirModel.AnyType anyType) where T : GirModel.Type => anyType.TryPickT0(out var type, out _) && type is T; + public static bool Is(this GirModel.AnyType anyType, [NotNullWhen(true)] out T? type) where T : class, GirModel.Type + { + var result = anyType.TryPickT0(out var t, out _) && t is T; + if (result) + type = (T) t; + else + type = null; + + return result; + } + public static bool IsArray(this GirModel.AnyType anyType) where T : GirModel.Type => anyType.TryPickT1(out var arrayType, out _) && arrayType is GirModel.StandardArrayType && arrayType.AnyType.Is(); + public static bool IsArray(this GirModel.AnyType anyType, [NotNullWhen(true)] out T? type) where T : class, GirModel.Type + { + type = null; + return anyType.TryPickT1(out var arrayType, out _) + && arrayType is GirModel.StandardArrayType + && arrayType.AnyType.Is(out type); + } + public static bool IsGLibPtrArray(this GirModel.AnyType anyType) => anyType.TryPickT1(out var arrayType, out _) && arrayType is GirModel.PointerArrayType; @@ -19,6 +39,14 @@ public static bool IsGLibPtrArray(this GirModel.AnyType anyType) where T : Gi && arrayType is GirModel.PointerArrayType && arrayType.AnyType.Is(); + public static bool IsGLibPtrArray(this GirModel.AnyType anyType, [NotNullWhen(true)] out T? type) where T : class, GirModel.Type + { + type = null; + return anyType.TryPickT1(out var arrayType, out _) + && arrayType is GirModel.PointerArrayType + && arrayType.AnyType.Is(out type); + } + public static bool IsGLibByteArray(this GirModel.AnyType anyType) => anyType.TryPickT1(out var arrayType, out _) && arrayType is GirModel.ByteArrayType; @@ -32,6 +60,18 @@ public static bool IsAlias(this GirModel.AnyType anyType) where T : GirModel. => anyType.TryPickT0(out var type, out _) && type is GirModel.Alias { Type: T }; + public static bool IsAlias(this GirModel.AnyType anyType, [NotNullWhen(true)] out T? type) where T : class, GirModel.Type + { + var result = anyType.TryPickT0(out var t, out _) && t is GirModel.Alias { Type: T }; + + if (result) + type = (T) ((GirModel.Alias) t).Type; + else + type = null; + + return result; + } + public static bool IsArrayAlias(this GirModel.AnyType anyType) where T : GirModel.Type => anyType.TryPickT1(out var arrayType, out _) && arrayType is GirModel.StandardArrayType diff --git a/src/Libs/GLib-2.0/GLib-2.0.csproj b/src/Libs/GLib-2.0/GLib-2.0.csproj index 44a9af04c..c033cbbfa 100644 --- a/src/Libs/GLib-2.0/GLib-2.0.csproj +++ b/src/Libs/GLib-2.0/GLib-2.0.csproj @@ -6,7 +6,7 @@ - Internal\ImportResolver.Generated.cs + GObject\ImportResolver.Generated.cs diff --git a/src/Libs/GLib-2.0/Internal/Functions.cs b/src/Libs/GLib-2.0/GObject/Functions.cs similarity index 88% rename from src/Libs/GLib-2.0/Internal/Functions.cs rename to src/Libs/GLib-2.0/GObject/Functions.cs index 24eb2183c..cdc6cdd62 100644 --- a/src/Libs/GLib-2.0/Internal/Functions.cs +++ b/src/Libs/GLib-2.0/GObject/Functions.cs @@ -5,9 +5,9 @@ * Important: This are functions which are part of GObject but made available manually in GLib */ -namespace GLib.Internal; +namespace GObject.Internal; -public partial class Functions +internal class Functions { [DllImport(ImportResolver.Library, EntryPoint = "g_boxed_copy")] public static extern IntPtr BoxedCopy(nuint boxedType, IntPtr srcBoxed); diff --git a/src/Libs/GLib-2.0/Internal/BoxedHandle.cs b/src/Libs/GLib-2.0/Internal/BoxedHandle.cs deleted file mode 100644 index 02d1462de..000000000 --- a/src/Libs/GLib-2.0/Internal/BoxedHandle.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace GLib.Internal; - -public class BoxedHandle : SafeHandle where T : NativeGTypeProvider -{ - public sealed override bool IsInvalid => handle == IntPtr.Zero; - - public BoxedHandle(IntPtr handle, bool ownsHandle) : base(IntPtr.Zero, ownsHandle) - { - if (!ownsHandle) - handle = Functions.BoxedCopy(GetGType(), handle); - - SetHandle(handle); - } - - protected override bool ReleaseHandle() - { - Functions.BoxedFree(GetGType(), handle); - return true; - } - - private static nuint GetGType() - { -#if NET7_0_OR_GREATER - return T.GetGType(); -#else - return NativeGTypeProviderHelper.GetGType(); -#endif - } -} - -public class InitiallyUnownedBoxedHandle : BoxedHandle where T : NativeGTypeProvider -{ - public InitiallyUnownedBoxedHandle(IntPtr handle) : base(handle, false) - { - } -} - -public class OwnedBoxedHandle : BoxedHandle where T : NativeGTypeProvider -{ - public OwnedBoxedHandle(IntPtr handle) : base(handle, true) - { - } -} diff --git a/src/Libs/GLib-2.0/Public/Bytes.cs b/src/Libs/GLib-2.0/Public/Bytes.cs index ba11c034c..f1ff497ec 100644 --- a/src/Libs/GLib-2.0/Public/Bytes.cs +++ b/src/Libs/GLib-2.0/Public/Bytes.cs @@ -5,25 +5,15 @@ namespace GLib; public sealed partial class Bytes : IDisposable { - #region Fields - private long _size; - #endregion - - #region Constructors - partial void Initialize() { - _size = (long) Internal.Bytes.GetSize(_handle); + _size = (long) Internal.Bytes.GetSize(Handle); GC.AddMemoryPressure(_size); } - #endregion - - #region Methods - - public static Bytes From(Span data) + public static Bytes New(Span data) { var obj = new Bytes(Internal.Bytes.New(ref MemoryMarshal.GetReference(data), (nuint) data.Length)); return obj; @@ -31,9 +21,7 @@ public static Bytes From(Span data) public void Dispose() { - _handle.Dispose(); + Handle.Dispose(); GC.RemoveMemoryPressure(_size); } - - #endregion } diff --git a/src/Libs/GLib-2.0/Public/MainContext.cs b/src/Libs/GLib-2.0/Public/MainContext.cs deleted file mode 100644 index 24da1ed18..000000000 --- a/src/Libs/GLib-2.0/Public/MainContext.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace GLib; - -public partial class MainContext -{ - public static MainContext New() - => new(Internal.MainContext.New()); - - public static MainContext Default() - => new(Internal.MainContext.Default()); -} diff --git a/src/Libs/GLib-2.0/Public/MainLoop.cs b/src/Libs/GLib-2.0/Public/MainLoop.cs index da55b38b2..bf21a6d19 100644 --- a/src/Libs/GLib-2.0/Public/MainLoop.cs +++ b/src/Libs/GLib-2.0/Public/MainLoop.cs @@ -4,25 +4,6 @@ namespace GLib; public sealed partial class MainLoop { - public MainLoop(MainContext context, bool isRunning = false) - : this(context.Handle, isRunning) { } - - public MainLoop() : this(Internal.MainContextNullHandle.Instance, false) { } - - private MainLoop(Internal.MainContextHandle context, bool isRunning) - { - _handle = Internal.MainLoop.New(context, isRunning); - } - - public MainContext GetContext() - { - return new MainContext(Internal.MainLoop.GetContext(Handle)); - } - - public bool IsRunning() => Internal.MainLoop.IsRunning(Handle); - - public void Run() => Internal.MainLoop.Run(Handle); - public void RunWithSynchronizationContext() { var original = SynchronizationContext.Current; @@ -38,6 +19,4 @@ public void RunWithSynchronizationContext() SynchronizationContext.SetSynchronizationContext(original); } } - - public void Quit() => Internal.MainLoop.Quit(Handle); } diff --git a/src/Libs/GLib-2.0/Public/Variant.cs b/src/Libs/GLib-2.0/Public/Variant.cs index 7e660f4ec..0391a19fd 100644 --- a/src/Libs/GLib-2.0/Public/Variant.cs +++ b/src/Libs/GLib-2.0/Public/Variant.cs @@ -91,9 +91,3 @@ public void Dispose() Handle.Dispose(); } } - -public static class VariantExtension -{ - public static VariantHandle GetSafeHandle(this Variant? variant) - => variant is null ? VariantNullHandle.Instance : variant.Handle; -} diff --git a/src/Libs/GLib-2.0/Public/VariantType.cs b/src/Libs/GLib-2.0/Public/VariantType.cs index cefc6d6af..1105e4400 100644 --- a/src/Libs/GLib-2.0/Public/VariantType.cs +++ b/src/Libs/GLib-2.0/Public/VariantType.cs @@ -5,30 +5,12 @@ namespace GLib; public partial class VariantType : IDisposable { - #region Static Member - - public static readonly VariantType String = new VariantType("s"); - public static readonly VariantType Variant = new VariantType("v"); - - #endregion - - #region Constructors - - public VariantType(string type) : this(Internal.VariantType.New(Internal.NonNullableUtf8StringOwnedHandle.Create(type))) { } - - #endregion - - #region Methods + public static readonly VariantType String = New("s"); + public static readonly VariantType Variant = New("v"); public override string ToString() => Internal.VariantType.PeekString(Handle).ConvertToString(); - #endregion - - #region IDisposable Implementation - public void Dispose() => Handle.Dispose(); - - #endregion } diff --git a/src/Libs/GdkPixbuf-2.0/Public/PixbufLoader.cs b/src/Libs/GdkPixbuf-2.0/Public/PixbufLoader.cs index 6209f7679..c65291a99 100644 --- a/src/Libs/GdkPixbuf-2.0/Public/PixbufLoader.cs +++ b/src/Libs/GdkPixbuf-2.0/Public/PixbufLoader.cs @@ -11,7 +11,7 @@ public static Pixbuf FromBytes(byte[] data) try { - using var bytes = Bytes.From(data); + using var bytes = Bytes.New(data); Internal.PixbufLoader.WriteBytes(handle, bytes.Handle, out var error); diff --git a/src/Libs/Gio-2.0/Public/DBusConnection.cs b/src/Libs/Gio-2.0/Public/DBusConnection.cs index ee60066d5..dbb3e7429 100644 --- a/src/Libs/Gio-2.0/Public/DBusConnection.cs +++ b/src/Libs/Gio-2.0/Public/DBusConnection.cs @@ -40,22 +40,8 @@ public Task CallAsync(string busName, string objectPath, string interfa Internal.DBusConnection.Call(Handle, GLib.Internal.NullableUtf8StringOwnedHandle.Create(busName), GLib.Internal.NonNullableUtf8StringOwnedHandle.Create(objectPath), GLib.Internal.NonNullableUtf8StringOwnedHandle.Create(interfaceName), GLib.Internal.NonNullableUtf8StringOwnedHandle.Create(methodName), - parameters.GetSafeHandle(), GLib.Internal.VariantTypeNullHandle.Instance, DBusCallFlags.None, -1, IntPtr.Zero, callbackHandler.NativeCallback, IntPtr.Zero); + parameters?.Handle ?? GLib.Internal.VariantNullHandle.Instance, GLib.Internal.VariantTypeUnownedHandle.NullHandle, DBusCallFlags.None, -1, IntPtr.Zero, callbackHandler.NativeCallback, IntPtr.Zero); return tcs.Task; } - - public Variant Call(string busName, string objectPath, string interfaceName, string methodName, Variant? parameters = null) - { - var parameterHandle = parameters?.Handle ?? GLib.Internal.VariantNullHandle.Instance; - var ret = Internal.DBusConnection.CallSync(Handle, - GLib.Internal.NullableUtf8StringOwnedHandle.Create(busName), GLib.Internal.NonNullableUtf8StringOwnedHandle.Create(objectPath), - GLib.Internal.NonNullableUtf8StringOwnedHandle.Create(interfaceName), GLib.Internal.NonNullableUtf8StringOwnedHandle.Create(methodName), - parameterHandle, GLib.Internal.VariantTypeNullHandle.Instance, DBusCallFlags.None, 9999, IntPtr.Zero, out var error); - - if (!error.IsInvalid) - throw new GException(error); - - return new Variant(ret); - } } diff --git a/src/Native/GirTestLib/girtest-opaque-record-tester.c b/src/Native/GirTestLib/girtest-opaque-record-tester.c deleted file mode 100644 index b067ee05c..000000000 --- a/src/Native/GirTestLib/girtest-opaque-record-tester.c +++ /dev/null @@ -1,62 +0,0 @@ -#include "girtest-opaque-record-tester.h" - -/** - * GirTestOpaqueRecordTester: - * - * Just an opaque record. - */ -struct _GirTestOpaqueRecordTester -{ - int ref_count; -}; - -G_DEFINE_BOXED_TYPE (GirTestOpaqueRecordTester, girtest_opaque_record_tester, girtest_opaque_record_tester_ref, girtest_opaque_record_tester_unref) - -/** - * girtest_opaque_record_tester_new: (constructor) - * - * Returns: (transfer full): a new `GirTestOpaqueRecordTester` - **/ -GirTestOpaqueRecordTester * -girtest_opaque_record_tester_new () -{ - GirTestOpaqueRecordTester *result; - result = g_new0 (GirTestOpaqueRecordTester, 1); - result->ref_count = 1; - return result; -} - -/** - * girtest_opaque_record_tester_ref: - * @self: a `GirTestRecordTester` - * - * Increments the reference count on `data`. - * - * Returns: (transfer full): the data. - **/ -GirTestOpaqueRecordTester * -girtest_opaque_record_tester_ref (GirTestOpaqueRecordTester *self) -{ - g_return_val_if_fail (self != NULL, NULL); - self->ref_count += 1; - return self; -} - -/** - * girtrest_opaque_record_tester_unref: - * @self: (transfer full): a `GirTestOpaqueRecordTester` - * - * Decrements the reference count on `data` and frees the - * data if the reference count is 0. - **/ -void -girtest_opaque_record_tester_unref (GirTestOpaqueRecordTester *self) -{ - g_return_if_fail (self != NULL); - - self->ref_count -= 1; - if (self->ref_count > 0) - return; - - g_free (self); -} diff --git a/src/Native/GirTestLib/girtest-opaque-record-tester.h b/src/Native/GirTestLib/girtest-opaque-record-tester.h deleted file mode 100644 index 676e60e69..000000000 --- a/src/Native/GirTestLib/girtest-opaque-record-tester.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include - -G_BEGIN_DECLS - -typedef struct _GirTestOpaqueRecordTester GirTestOpaqueRecordTester; -#define GIRTEST_TYPE_OPAQUE_RECORD_TESTER (girtest_opaque_record_tester_get_type()) - -GType girtest_opaque_record_tester_get_type (void) G_GNUC_CONST; - -GirTestOpaqueRecordTester * girtest_opaque_record_tester_new (); -GirTestOpaqueRecordTester * girtest_opaque_record_tester_ref (GirTestOpaqueRecordTester *self); -void girtest_opaque_record_tester_unref(GirTestOpaqueRecordTester *self); - -G_END_DECLS diff --git a/src/Native/GirTestLib/girtest-opaque-typed-record-tester.c b/src/Native/GirTestLib/girtest-opaque-typed-record-tester.c new file mode 100644 index 000000000..01b303ac8 --- /dev/null +++ b/src/Native/GirTestLib/girtest-opaque-typed-record-tester.c @@ -0,0 +1,339 @@ +#include "girtest-opaque-typed-record-tester.h" + +/** + * GirTestOpaqueTypedRecordTester: + * + * Just an opaque record. + */ +struct _GirTestOpaqueTypedRecordTester +{ + int ref_count; +}; + +G_DEFINE_BOXED_TYPE (GirTestOpaqueTypedRecordTester, girtest_opaque_typed_record_tester, girtest_opaque_typed_record_tester_ref, girtest_opaque_typed_record_tester_unref) + +/** + * girtest_opaque_typed_record_tester_new: (constructor) + * + * Returns: (transfer full): a new `GirTestOpaqueTypedRecordTester` + **/ +GirTestOpaqueTypedRecordTester * +girtest_opaque_typed_record_tester_new () +{ + GirTestOpaqueTypedRecordTester *result; + result = g_new0 (GirTestOpaqueTypedRecordTester, 1); + result->ref_count = 1; + return result; +} + +/** + * girtest_opaque_typed_record_tester_try_new: + * @returnNull: TRUE to return null, FALSE to create a new instance. + * + * Returns: (transfer full) (nullable): a new `GirTestOpaqueTypedRecordTester` or NULL + **/ +GirTestOpaqueTypedRecordTester * +girtest_opaque_typed_record_tester_try_new (gboolean returnNull) +{ + if(returnNull) + return NULL; + + return girtest_opaque_typed_record_tester_new(); +} + +/** + * girtest_opaque_typed_record_tester_ref: + * @self: a `GirTestRecordTester` + * + * Increments the reference count on `data`. + * + * Returns: (transfer full): the data. + **/ +GirTestOpaqueTypedRecordTester * +girtest_opaque_typed_record_tester_ref (GirTestOpaqueTypedRecordTester *self) +{ + g_return_val_if_fail (self != NULL, NULL); + self->ref_count += 1; + return self; +} + +/** + * girtest_opaque_typed_record_tester_try_ref: + * @self: a `GirTestRecordTester` + * @returnNull: TRUE to return NULL, otherwise FALSE + * + * Increments the reference count on `data`. + * + * Returns: (transfer full) (nullable): the data or NULL + **/ +GirTestOpaqueTypedRecordTester * +girtest_opaque_typed_record_tester_try_ref (GirTestOpaqueTypedRecordTester *self, gboolean returnNull) +{ + if(returnNull) + return NULL; + + return girtest_opaque_typed_record_tester_ref(self); +} + +/** + * girtest_opaque_typed_record_tester_mirror: + * @data: a `GirTestRecordTester` + * + * Mirrors the given data as the return value. Ownership is not transferred. + * + * Returns: (transfer none): the mirrored data. + **/ +GirTestOpaqueTypedRecordTester * +girtest_opaque_typed_record_tester_mirror(GirTestOpaqueTypedRecordTester *data) +{ + return data; +} + +/** + * girtest_opaque_typed_record_tester_nullable_mirror: + * @data: a `GirTestRecordTester` + * @mirror: true to mirror data, false to return NULL + * + * Mirrors the given data as the return value if @mirror is true. Ownership is not transferred. + * + * Returns: (transfer none) (nullable): the mirrored data or NULL. + **/ +GirTestOpaqueTypedRecordTester * +girtest_opaque_typed_record_tester_nullable_mirror(GirTestOpaqueTypedRecordTester *data, gboolean mirror) +{ + if(!mirror) + return NULL; + + return data; +} + +/** + * girtrest_opaque_typed_record_tester_unref: + * @self: (transfer full): a `GirTestOpaqueTypedRecordTester` + * + * Decrements the reference count on `data` and frees the + * data if the reference count is 0. + **/ +void +girtest_opaque_typed_record_tester_unref (GirTestOpaqueTypedRecordTester *self) +{ + g_return_if_fail (self != NULL); + + self->ref_count -= 1; + if (self->ref_count > 0) + return; + + g_free (self); +} + +/** + * girtest_opaque_typed_record_tester_get_ref_count: + * @self: a `GirTestOpaqueTypedRecordTester` + * + * Returns: The current ref count of the opaque record. + **/ +int +girtest_opaque_typed_record_tester_get_ref_count(GirTestOpaqueTypedRecordTester *self) +{ + g_return_val_if_fail (self != NULL, -1); + return self->ref_count; +} + +/** + * girtest_opaque_typed_record_tester_try_get_ref_count: + * @dummy: not used + * @self: (nullable): a `GirTestOpaqueTypedRecordTester` + * + * Returns: The current ref count of the opaque record or -1 if @self is NULL + **/ +int girtest_opaque_typed_record_tester_try_get_ref_count(int dummy, GirTestOpaqueTypedRecordTester *self) +{ + if(self == NULL) + return -1; + + return self->ref_count; +} + +/** + * girtest_opaque_typed_record_tester_take_and_unref: + * @self: (transfer full): a `GirTestOpaqueTypedRecordTester` + * + * Takes ownership and decrements the reference count on `data` and frees the + * data if the reference count is 0. + **/ +void +girtest_opaque_typed_record_tester_take_and_unref(GirTestOpaqueTypedRecordTester *self) +{ + girtest_opaque_typed_record_tester_unref(self); +} + +/** + * girtest_opaque_typed_record_tester_take_and_unref_func: + * @dummy: Just an unused dummy value + * @data: (transfer full): a `GirTestOpaqueTypedRecordTester` + * + * Takes ownership and decrements the reference count on `data` and frees the + * data if the reference count is 0. + **/ +void +girtest_opaque_typed_record_tester_take_and_unref_func(int dummy, GirTestOpaqueTypedRecordTester *data) +{ + girtest_opaque_typed_record_tester_take_and_unref(data); +} + +/** + * girtest_opaque_typed_record_tester_take_and_unref_func_nullable: + * @dummy: Just an unused dummy value + * @data: (transfer full) (nullable): a `GirTestOpaqueTypedRecordTester` + * + * Takes ownership and decrements the reference count on `data` and frees the + * data if the reference count is 0. + **/ +void +girtest_opaque_typed_record_tester_take_and_unref_func_nullable(int dummy, GirTestOpaqueTypedRecordTester *data) +{ + if(data == NULL) + return; + + girtest_opaque_typed_record_tester_take_and_unref(data); +} + +/** + * girtest_opaque_typed_record_tester_get_ref_count_sum: + * @data: (array length=size): an array of `GirTestOpaqueTypedRecordTester` pointers + * @size: The length of @data + * + * Returns: The count of all refs of the @data. + **/ +int girtest_opaque_typed_record_tester_get_ref_count_sum(GirTestOpaqueTypedRecordTester * const *data, gsize size) +{ + int sum = 0; + + for (int i = 0; i < size; i++) + { + sum = sum + girtest_opaque_typed_record_tester_get_ref_count(data[i]); + } + + return sum; +} + +/** + * girtest_opaque_typed_record_tester_get_ref_count_sum_nullable: + * @data: (nullable) (array length=size): an array of `GirTestOpaqueTypedRecordTester` pointers + * @size: The length of @data + * + * Returns: The count of all refs of the @data. -1 if NULL is supplied as @data. + **/ +int girtest_opaque_typed_record_tester_get_ref_count_sum_nullable(GirTestOpaqueTypedRecordTester * const *data, gsize size) +{ + if(data == NULL) + return -1; + + return girtest_opaque_typed_record_tester_get_ref_count_sum(data, size); +} + +/** + * girtest_opaque_typed_record_tester_run_callback_return_no_ownership_transfer: + * @callback: (scope call): a callback + * + * Calls the callback and returns the newly created instance. + * + * Returns: (transfer none): a GirTestOpaqueTypedRecordTester + **/ +GirTestOpaqueTypedRecordTester * +girtest_opaque_typed_record_tester_run_callback_return_no_ownership_transfer(GirTestCreateOpaqueTypedRecordTesterNoOwnershipTransfer callback) +{ + return callback(); +} + +/** + * girtest_opaque_typed_record_tester_run_callback_return_no_ownership_transfer_nullable: + * @callback: (scope call): a callback + * + * Calls the callback and returns the newly created instance or NULL + * + * Returns: (transfer none) (nullable): a GirTestOpaqueTypedRecordTester + **/ +GirTestOpaqueTypedRecordTester * girtest_opaque_typed_record_tester_run_callback_return_no_ownership_transfer_nullable(GirTestCreateOpaqueTypedRecordTesterNoOwnershipTransferNullable callback) +{ + return callback(); +} + +/** + * girtest_opaque_typed_record_tester_run_callback_return_full_ownership_transfer: + * @callback: (scope call): a callback + * + * Calls the callback and returns the newly created instance. + * + * Returns: (transfer full): a GirTestOpaqueTypedRecordTester + **/ +GirTestOpaqueTypedRecordTester * girtest_opaque_typed_record_tester_run_callback_return_full_ownership_transfer(GirTestCreateOpaqueTypedRecordTesterFullOwnershipTransfer callback) +{ + return callback(); +} + +/** + * girtest_opaque_typed_record_tester_run_callback_return_full_ownership_transfer_nullable: + * @callback: (scope call): a callback + * + * Calls the callback and returns the newly created instance. + * + * Returns: (transfer full) (nullable): a GirTestOpaqueTypedRecordTester or NULL + **/ +GirTestOpaqueTypedRecordTester * girtest_opaque_typed_record_tester_run_callback_return_full_ownership_transfer_nullable(GirTestCreateOpaqueTypedRecordTesterFullOwnershipTransferNullable callback) +{ + return callback(); +} + +/** + * girtest_opaque_typed_record_tester_run_callback_parameter_full_ownership_transfer: + * @callback: (scope call): a callback + * + * Calls the callback and supplies a new OpaqueTypedRecordTester. + **/ +void +girtest_opaque_typed_record_tester_run_callback_parameter_full_ownership_transfer(GirTestGetOpaqueTypedRecordTesterFullOwnershipTransfer callback) +{ + callback(girtest_opaque_typed_record_tester_new()); +} + +/** + * girtest_opaque_typed_record_tester_run_callback_parameter_full_ownership_transfer_nullable: + * @useNull: TRUE to pass null to the callback, otherwise FALSE. + * @callback: (scope call): a callback + * + * Calls the callback and supplies a new OpaqueTypedRecordTester if @useNull is FALSE. + **/ +void girtest_opaque_typed_record_tester_run_callback_parameter_full_ownership_transfer_nullable(gboolean useNull, GirTestGetOpaqueTypedRecordTesterFullOwnershipTransferNullable callback) +{ + if(useNull) + callback(NULL); + else + callback(girtest_opaque_typed_record_tester_new()); +} + +/** + * girtest_opaque_typed_record_tester_run_callback_parameter_no_ownership_transfer: + * @callback: (scope call): a callback + * @data: (transfer none): A GirTestOpaqueTypedRecordTester + * + * Calls the callback and supplies the given OpaqueTypedRecordTester. + **/ +void +girtest_opaque_typed_record_tester_run_callback_parameter_no_ownership_transfer(GirTestGetOpaqueTypedRecordTesterNoOwnershipTransfer callback, GirTestOpaqueTypedRecordTester *data) +{ + callback(data); +} + +/** + * girtest_opaque_typed_record_tester_run_callback_parameter_no_ownership_transfer_nullable: + * @callback: (scope call): a callback + * @data: (transfer none) (nullable): A GirTestOpaqueTypedRecordTester + * + * Calls the callback and supplies the given OpaqueTypedRecordTester. + **/ +void +girtest_opaque_typed_record_tester_run_callback_parameter_no_ownership_transfer_nullable(GirTestGetOpaqueTypedRecordTesterNoOwnershipTransferNullable callback, GirTestOpaqueTypedRecordTester *data) +{ + callback(data); +} \ No newline at end of file diff --git a/src/Native/GirTestLib/girtest-opaque-typed-record-tester.h b/src/Native/GirTestLib/girtest-opaque-typed-record-tester.h new file mode 100644 index 000000000..64a31d378 --- /dev/null +++ b/src/Native/GirTestLib/girtest-opaque-typed-record-tester.h @@ -0,0 +1,86 @@ +#pragma once + +#include + +G_BEGIN_DECLS + +typedef struct _GirTestOpaqueTypedRecordTester GirTestOpaqueTypedRecordTester; +#define GIRTEST_TYPE_OPAQUE_TYPED_RECORD_TESTER (girtest_opaque_typed_record_tester_get_type()) + +GType girtest_opaque_typed_record_tester_get_type (void) G_GNUC_CONST; + +/** + * GirTestCreateOpaqueTypedRecordTesterNoOwnershipTransfer: + * + * Returns: (transfer none): a new OpaqueRecordTester. + */ +typedef GirTestOpaqueTypedRecordTester* (*GirTestCreateOpaqueTypedRecordTesterNoOwnershipTransfer) (); + +/** + * GirTestCreateOpaqueTypedRecordTesterNoOwnershipTransferNullable: + * + * Returns: (transfer none) (nullable): a new OpaqueRecordTester or NULL. + */ +typedef GirTestOpaqueTypedRecordTester* (*GirTestCreateOpaqueTypedRecordTesterNoOwnershipTransferNullable) (); + +/** + * GirTestCreateOpaqueTypedRecordTesterFullOwnershipTransfer: + * + * Returns: (transfer full): a new OpaqueTypedRecordTester. + */ +typedef GirTestOpaqueTypedRecordTester* (*GirTestCreateOpaqueTypedRecordTesterFullOwnershipTransfer) (); + +/** + * GirTestCreateOpaqueTypedRecordTesterFullOwnershipTransferNullable: + * + * Returns: (transfer full) (nullable): a new OpaqueTypedRecordTester or NULL. + */ +typedef GirTestOpaqueTypedRecordTester* (*GirTestCreateOpaqueTypedRecordTesterFullOwnershipTransferNullable) (); + +/** + * GirTestGetOpaqueTypedRecordTesterFullOwnershipTransfer: + * @data: (transfer full): An OpaqueTypedRecordTester + */ +typedef void (*GirTestGetOpaqueTypedRecordTesterFullOwnershipTransfer) (GirTestOpaqueTypedRecordTester *data); + +/** + * GirTestGetOpaqueTypedRecordTesterFullOwnershipTransferNullable: + * @data: (transfer full) (nullable): An OpaqueTypedRecordTester + */ +typedef void (*GirTestGetOpaqueTypedRecordTesterFullOwnershipTransferNullable) (GirTestOpaqueTypedRecordTester *data); + +/** + * GirTestGetOpaqueTypedRecordTesterNoOwnershipTransfer: + * @data: (transfer none): An OpaqueTypedRecordTester + */ +typedef void (*GirTestGetOpaqueTypedRecordTesterNoOwnershipTransfer) (GirTestOpaqueTypedRecordTester *data); + +/** + * GirTestGetOpaqueTypedRecordTesterNoOwnershipTransferNullable: + * @data: (transfer none) (nullable): An OpaqueTypedRecordTester + */ +typedef void (*GirTestGetOpaqueTypedRecordTesterNoOwnershipTransferNullable) (GirTestOpaqueTypedRecordTester *data); + +GirTestOpaqueTypedRecordTester * girtest_opaque_typed_record_tester_new (); +GirTestOpaqueTypedRecordTester * girtest_opaque_typed_record_tester_try_new (gboolean returnNull); +GirTestOpaqueTypedRecordTester * girtest_opaque_typed_record_tester_ref (GirTestOpaqueTypedRecordTester *self); +GirTestOpaqueTypedRecordTester * girtest_opaque_typed_record_tester_try_ref (GirTestOpaqueTypedRecordTester *self, gboolean returnNull); +GirTestOpaqueTypedRecordTester * girtest_opaque_typed_record_tester_mirror(GirTestOpaqueTypedRecordTester *data); +GirTestOpaqueTypedRecordTester * girtest_opaque_typed_record_tester_nullable_mirror(GirTestOpaqueTypedRecordTester *data, gboolean mirror); +void girtest_opaque_typed_record_tester_unref(GirTestOpaqueTypedRecordTester *self); +int girtest_opaque_typed_record_tester_get_ref_count(GirTestOpaqueTypedRecordTester *self); +int girtest_opaque_typed_record_tester_try_get_ref_count(int dummy, GirTestOpaqueTypedRecordTester *self); +void girtest_opaque_typed_record_tester_take_and_unref(GirTestOpaqueTypedRecordTester *self); +void girtest_opaque_typed_record_tester_take_and_unref_func(int dummy, GirTestOpaqueTypedRecordTester *data); +void girtest_opaque_typed_record_tester_take_and_unref_func_nullable(int dummy, GirTestOpaqueTypedRecordTester *data); +int girtest_opaque_typed_record_tester_get_ref_count_sum(GirTestOpaqueTypedRecordTester * const *data, gsize size); +int girtest_opaque_typed_record_tester_get_ref_count_sum_nullable(GirTestOpaqueTypedRecordTester * const *data, gsize size); +GirTestOpaqueTypedRecordTester * girtest_opaque_typed_record_tester_run_callback_return_no_ownership_transfer(GirTestCreateOpaqueTypedRecordTesterNoOwnershipTransfer callback); +GirTestOpaqueTypedRecordTester * girtest_opaque_typed_record_tester_run_callback_return_no_ownership_transfer_nullable(GirTestCreateOpaqueTypedRecordTesterNoOwnershipTransferNullable callback); +GirTestOpaqueTypedRecordTester * girtest_opaque_typed_record_tester_run_callback_return_full_ownership_transfer(GirTestCreateOpaqueTypedRecordTesterFullOwnershipTransfer callback); +GirTestOpaqueTypedRecordTester * girtest_opaque_typed_record_tester_run_callback_return_full_ownership_transfer_nullable(GirTestCreateOpaqueTypedRecordTesterFullOwnershipTransferNullable callback); +void girtest_opaque_typed_record_tester_run_callback_parameter_full_ownership_transfer(GirTestGetOpaqueTypedRecordTesterFullOwnershipTransfer callback); +void girtest_opaque_typed_record_tester_run_callback_parameter_full_ownership_transfer_nullable(gboolean useNull, GirTestGetOpaqueTypedRecordTesterFullOwnershipTransferNullable callback); +void girtest_opaque_typed_record_tester_run_callback_parameter_no_ownership_transfer(GirTestGetOpaqueTypedRecordTesterNoOwnershipTransfer callback, GirTestOpaqueTypedRecordTester *data); +void girtest_opaque_typed_record_tester_run_callback_parameter_no_ownership_transfer_nullable(GirTestGetOpaqueTypedRecordTesterNoOwnershipTransferNullable callback, GirTestOpaqueTypedRecordTester *data); +G_END_DECLS diff --git a/src/Native/GirTestLib/girtest.h b/src/Native/GirTestLib/girtest.h index 3321555fe..93713ede7 100644 --- a/src/Native/GirTestLib/girtest.h +++ b/src/Native/GirTestLib/girtest.h @@ -9,7 +9,7 @@ #include "girtest-constant-tester.h" #include "girtest-error-tester.h" #include "girtest-integer-array-tester.h" -#include "girtest-opaque-record-tester.h" +#include "girtest-opaque-typed-record-tester.h" #include "girtest-primitive-value-type-tester.h" #include "girtest-property-tester.h" #include "girtest-record-tester.h" diff --git a/src/Native/GirTestLib/meson.build b/src/Native/GirTestLib/meson.build index e1e1245ea..a57d2c0e6 100644 --- a/src/Native/GirTestLib/meson.build +++ b/src/Native/GirTestLib/meson.build @@ -12,7 +12,7 @@ header_files = [ 'girtest-constant-tester.h', 'girtest-error-tester.h', 'girtest-integer-array-tester.h', - 'girtest-opaque-record-tester.h', + 'girtest-opaque-typed-record-tester.h', 'girtest-primitive-value-type-tester.h', 'girtest-property-tester.h', 'girtest-record-tester.h', @@ -32,7 +32,7 @@ source_files = [ 'girtest-class-tester.c', 'girtest-error-tester.c', 'girtest-integer-array-tester.c', - 'girtest-opaque-record-tester.c', + 'girtest-opaque-typed-record-tester.c', 'girtest-primitive-value-type-tester.c', 'girtest-property-tester.c', 'girtest-record-tester.c', diff --git a/src/Samples/Gio-2.0/DBusNotification/SendNotification.cs b/src/Samples/Gio-2.0/DBusNotification/SendNotification.cs index a7dd79732..a7afe1442 100644 --- a/src/Samples/Gio-2.0/DBusNotification/SendNotification.cs +++ b/src/Samples/Gio-2.0/DBusNotification/SendNotification.cs @@ -1,6 +1,7 @@ using System; using Gio; using GLib; +using Array = System.Array; namespace Sample; @@ -20,12 +21,12 @@ public static void SendNotification() Variant.Create(""), //Icon Variant.Create("Summary"), Variant.Create("Body"), - Variant.Create(new string[0]), + Variant.Create(Array.Empty()), Variant.CreateEmptyDictionary(VariantType.String, VariantType.Variant),//hints Variant.Create(999) ); - using Variant ret = bus.Call("org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications", "Notify", parameters); + using Variant ret = bus.CallSync("org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications", "Notify", parameters, null, DBusCallFlags.None, 9999, null); Console.WriteLine("Result: " + ret.Print(true)); } } diff --git a/src/Tests/Libs/GLib-2.0.Tests/Records/VariantTypeTest.cs b/src/Tests/Libs/GLib-2.0.Tests/Records/VariantTypeTest.cs index fb5134235..2251c23b2 100644 --- a/src/Tests/Libs/GLib-2.0.Tests/Records/VariantTypeTest.cs +++ b/src/Tests/Libs/GLib-2.0.Tests/Records/VariantTypeTest.cs @@ -21,7 +21,7 @@ public class VariantTypeTest : Test [DataRow("v")] public void CanCreateTypeFromString(string type) { - var variantType = new VariantType(type); + var variantType = VariantType.New(type); variantType.ToString().Should().Be(type); } diff --git a/src/Tests/Libs/GLib-2.0.Tests/SynchronizationContextTest.cs b/src/Tests/Libs/GLib-2.0.Tests/SynchronizationContextTest.cs index 053c04fa3..46e176db8 100644 --- a/src/Tests/Libs/GLib-2.0.Tests/SynchronizationContextTest.cs +++ b/src/Tests/Libs/GLib-2.0.Tests/SynchronizationContextTest.cs @@ -11,7 +11,7 @@ public class SynchronizationContextTest : Test [TestMethod] public void AsyncMethodIsExecutedOnMainLoopThread() { - var mainLoop = new MainLoop(); + var mainLoop = MainLoop.New(null, false); var context = mainLoop.GetContext(); var source = Functions.TimeoutSourceNew(1); source.Attach(context); @@ -35,7 +35,7 @@ public void AsyncMethodIsExecutedOnMainLoopThread() [TestMethod] public void ExceptionInAsyncMethodCanBeHandledViaUnhandledExceptionHandler() { - var mainLoop = new MainLoop(); + var mainLoop = MainLoop.New(null, false); var context = mainLoop.GetContext(); var source = Functions.TimeoutSourceNew(1); source.Attach(context); diff --git a/src/Tests/Libs/GObject-2.0.Tests/Records/ValueTest.cs b/src/Tests/Libs/GObject-2.0.Tests/Records/ValueTest.cs index 598fef19d..5fc40b50d 100644 --- a/src/Tests/Libs/GObject-2.0.Tests/Records/ValueTest.cs +++ b/src/Tests/Libs/GObject-2.0.Tests/Records/ValueTest.cs @@ -23,9 +23,10 @@ public void ValueFromDataShouldContainGivenData(object data) [TestMethod] public void VariantFromDataShouldContainGivenData() { - var variant = GLib.Variant.Create("foo"); + var text = "foo"; + var variant = GLib.Variant.Create(text); var v = Value.From(variant); - v.Extract().GetString().Should().Be("foo"); + v.Extract().GetString().Should().Be(text); } [DataTestMethod] diff --git a/src/Tests/Libs/Gio-2.0.Tests/SimpleActionTest.cs b/src/Tests/Libs/Gio-2.0.Tests/SimpleActionTest.cs index 46ddfa230..686027125 100644 --- a/src/Tests/Libs/Gio-2.0.Tests/SimpleActionTest.cs +++ b/src/Tests/Libs/Gio-2.0.Tests/SimpleActionTest.cs @@ -11,7 +11,9 @@ public void TestActivate() { var action = SimpleAction.NewStateful("myname", GLib.VariantType.String, GLib.Variant.Create("foo")); - string result = action.GetState().GetString(); + var result = action.GetState().GetString(); + result.Should().Be("foo"); + action.OnActivate += (_, args) => { result = args.Parameter!.GetString(); diff --git a/src/Tests/Libs/GirTest-0.1.Tests/OpaqueTypedRecordTest.cs b/src/Tests/Libs/GirTest-0.1.Tests/OpaqueTypedRecordTest.cs new file mode 100644 index 000000000..da9d7a1e4 --- /dev/null +++ b/src/Tests/Libs/GirTest-0.1.Tests/OpaqueTypedRecordTest.cs @@ -0,0 +1,290 @@ +using System; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace GirTest.Tests; + +[TestClass, TestCategory("BindingTest")] +public class OpaqueTypedRecordTest : Test +{ + [TestMethod] + public void SupportsConstructorTransferFull() + { + var recordTester = OpaqueTypedRecordTester.New(); + recordTester.Handle.DangerousGetHandle().Should().NotBe(IntPtr.Zero); + } + + [TestMethod] + public void SupportsConstructorNullableTransferFull() + { + var recordTester = OpaqueTypedRecordTester.TryNew(false); + recordTester!.Handle.DangerousGetHandle().Should().NotBe(IntPtr.Zero); + + var recordTester2 = OpaqueTypedRecordTester.TryNew(true); + recordTester2.Should().BeNull(); + } + + [TestMethod] + public void SupportsReturnValueTransferFull() + { + var recordTester = OpaqueTypedRecordTester.New(); + var recordTester2 = recordTester.Ref(); + recordTester2.GetRefCount().Should().Be(2); + } + + [TestMethod] + public void SupportsReturnValueTransferNone() + { + var recordTester = OpaqueTypedRecordTester.New(); + var recordTester2 = recordTester.Mirror(); + + recordTester.GetRefCount().Should().Be(2); + recordTester2.GetRefCount().Should().Be(2); + + recordTester.Handle.DangerousGetHandle().Should().Be(recordTester2.Handle.DangerousGetHandle()); + } + + [TestMethod] + public void SupportsReturnValueNullableTransferNone() + { + var recordTester = OpaqueTypedRecordTester.New(); + var recordTester2 = recordTester.NullableMirror(true); + + recordTester.GetRefCount().Should().Be(2); + recordTester2!.GetRefCount().Should().Be(2); + + recordTester.Handle.DangerousGetHandle().Should().Be(recordTester2.Handle.DangerousGetHandle()); + + var recordTester3 = recordTester.NullableMirror(false); + recordTester3.Should().BeNull(); + } + + [TestMethod] + public void SupportsReturnValueNullableTransferFull() + { + var recordTester = OpaqueTypedRecordTester.New(); + var recordTester2 = recordTester.TryRef(false); + + recordTester.GetRefCount().Should().Be(2); + recordTester2!.GetRefCount().Should().Be(2); + + recordTester.Handle.DangerousGetHandle().Should().Be(recordTester2.Handle.DangerousGetHandle()); + + var recordTester3 = recordTester.TryRef(true); + recordTester3.Should().BeNull(); + } + + [TestMethod] + public void SupportsInstanceParameterTransferNone() + { + var recordTester = OpaqueTypedRecordTester.New(); + recordTester.GetRefCount().Should().Be(1); + } + + [TestMethod] + public void SupportsInstanceParameterTransferFull() + { + var recordTester = OpaqueTypedRecordTester.New(); + recordTester.GetRefCount().Should().Be(1); + recordTester.TakeAndUnref(); + recordTester.GetRefCount().Should().Be(1); + } + + [TestMethod] + public void SupportsParameterTransferFull() + { + var recordTester = OpaqueTypedRecordTester.New(); + recordTester.GetRefCount().Should().Be(1); + OpaqueTypedRecordTester.TakeAndUnrefFunc(0, recordTester); + recordTester.GetRefCount().Should().Be(1); + } + + [TestMethod] + public void SupportsParameterNullableTransferFull() + { + var recordTester = OpaqueTypedRecordTester.New(); + recordTester.GetRefCount().Should().Be(1); + OpaqueTypedRecordTester.TakeAndUnrefFuncNullable(0, recordTester); + recordTester.GetRefCount().Should().Be(1); + + OpaqueTypedRecordTester.TakeAndUnrefFuncNullable(0, null); + } + + [TestMethod] + public void SupportsParameterNullableTransferNone() + { + var result = OpaqueTypedRecordTester.TryGetRefCount(0, null); + result.Should().Be(-1); + + result = OpaqueTypedRecordTester.TryGetRefCount(0, OpaqueTypedRecordTester.New()); + result.Should().Be(1); + } + + [TestMethod] + public void SupportsParameterArrayWithLengthParameter() + { + var recordTester1 = OpaqueTypedRecordTester.New(); + var recordTester2 = OpaqueTypedRecordTester.New(); + + var result = OpaqueTypedRecordTester.GetRefCountSum(new[] { recordTester1, recordTester2 }); + result.Should().Be(2); + + OpaqueTypedRecordTester.GetRefCountSum(Array.Empty()).Should().Be(0); + } + + [TestMethod] + public void SupportsParameterNullableArrayWithLengthParameter() + { + var recordTester1 = OpaqueTypedRecordTester.New(); + var recordTester2 = OpaqueTypedRecordTester.New(); + + var result = OpaqueTypedRecordTester.GetRefCountSumNullable(new[] { recordTester1, recordTester2 }); + result.Should().Be(2); + + OpaqueTypedRecordTester.GetRefCountSumNullable(Array.Empty()).Should().Be(0); + OpaqueTypedRecordTester.GetRefCountSumNullable(null).Should().Be(-1); + } + + [TestMethod] + public void SupportsCallbackReturnNoOwnershipTransfer() + { + var recordTester = OpaqueTypedRecordTester.New(); + + OpaqueTypedRecordTester Create() + { + return recordTester; + } + + var recordTester2 = OpaqueTypedRecordTester.RunCallbackReturnNoOwnershipTransfer(Create); + + recordTester.GetRefCount().Should().Be(2); + recordTester2.GetRefCount().Should().Be(2); + recordTester.Handle.DangerousGetHandle().Should().Be(recordTester2.Handle.DangerousGetHandle()); + } + + [DataTestMethod] + [DataRow(true)] + [DataRow(false)] + public void SupportsCallbackReturnNoOwnershipTransferNullable(bool useNull) + { + OpaqueTypedRecordTester? Create() + { + return useNull ? null : OpaqueTypedRecordTester.New(); + } + + var recordTester2 = OpaqueTypedRecordTester.RunCallbackReturnNoOwnershipTransferNullable(Create); + if (useNull) + recordTester2.Should().BeNull(); + else + recordTester2.Should().NotBeNull(); + } + + [TestMethod] + public void SupportsCallbackReturnFullOwnershipTransfer() + { + var recordTester = OpaqueTypedRecordTester.New(); + + OpaqueTypedRecordTester Create() + { + return recordTester; + } + + var recordTester2 = OpaqueTypedRecordTester.RunCallbackReturnFullOwnershipTransfer(Create); + + recordTester.GetRefCount().Should().Be(2); + recordTester2.GetRefCount().Should().Be(2); + recordTester.Handle.DangerousGetHandle().Should().Be(recordTester2.Handle.DangerousGetHandle()); + } + + [DataTestMethod] + [DataRow(true)] + [DataRow(false)] + public void SupportsCallbackReturnFullOwnershipTransferNullable(bool useNull) + { + OpaqueTypedRecordTester? Create() + { + return useNull ? null : OpaqueTypedRecordTester.New(); + } + + var recordTester2 = OpaqueTypedRecordTester.RunCallbackReturnFullOwnershipTransferNullable(Create); + + if (useNull) + recordTester2.Should().BeNull(); + else + recordTester2.Should().NotBeNull(); + } + + [TestMethod] + public void SupportsCallbackParameterFullOwnershipTransfer() + { + var called = false; + + void Callback(OpaqueTypedRecordTester recordTester) + { + recordTester.GetRefCount().Should().Be(1); + called = true; + } + + OpaqueTypedRecordTester.RunCallbackParameterFullOwnershipTransfer(Callback); + + called.Should().BeTrue(); + } + + [DataTestMethod] + [DataRow(true)] + [DataRow(false)] + public void SupportsCallbackParameterFullOwnershipTransferNullable(bool useNull) + { + var called = false; + + void Callback(OpaqueTypedRecordTester? recordTester) + { + (recordTester is null).Should().Be(useNull); + called = true; + } + + OpaqueTypedRecordTester.RunCallbackParameterFullOwnershipTransferNullable(useNull, Callback); + called.Should().BeTrue(); + } + + [TestMethod] + public void SupportsCallbackParameterNoOwnershipTransfer() + { + var recordTester = OpaqueTypedRecordTester.New(); + var called = false; + + void Callback(OpaqueTypedRecordTester obj) + { + obj.GetRefCount().Should().Be(2); + obj.Handle.DangerousGetHandle().Should().Be(recordTester.Handle.DangerousGetHandle()); + called = true; + } + + OpaqueTypedRecordTester.RunCallbackParameterNoOwnershipTransfer(Callback, recordTester); + + called.Should().BeTrue(); + } + + [DataTestMethod] + [DataRow(true)] + [DataRow(false)] + public void SupportsCallbackParameterNoOwnershipTransferNullable(bool useNull) + { + var recordTester = useNull ? null : OpaqueTypedRecordTester.New(); + var called = false; + + void Callback(OpaqueTypedRecordTester? obj) + { + (obj is null).Should().Be(useNull); + + if (!useNull) + obj!.GetRefCount().Should().Be(2); + + called = true; + } + + OpaqueTypedRecordTester.RunCallbackParameterNoOwnershipTransferNullable(Callback, recordTester); + + called.Should().BeTrue(); + } +}