From c4058097d8081e95d9ddcb2cf67bf77194662587 Mon Sep 17 00:00:00 2001 From: badcel <1218031+badcel@users.noreply.github.com> Date: Sat, 8 Jun 2024 14:54:06 +0200 Subject: [PATCH 1/2] GirModel: Add copy/free func for records and unions --- src/Generation/GirLoader/Input/Record.cs | 6 ++++++ src/Generation/GirLoader/Input/Union.cs | 6 ++++++ src/Generation/GirLoader/Output/Record.GirModel.cs | 2 ++ src/Generation/GirLoader/Output/Record.cs | 7 ++++++- src/Generation/GirLoader/Output/RecordFactory.cs | 9 +++++++-- src/Generation/GirLoader/Output/Union.GirModel.cs | 2 ++ src/Generation/GirLoader/Output/Union.cs | 7 ++++++- src/Generation/GirLoader/Output/UnionFactory.cs | 9 +++++++-- .../GirLoader/PlatformSupport/Records/Record.GirModel.cs | 2 ++ .../GirLoader/PlatformSupport/Unions/Union.GirModel.cs | 2 ++ src/Generation/GirModel/Record.cs | 2 ++ src/Generation/GirModel/Union.cs | 2 ++ 12 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/Generation/GirLoader/Input/Record.cs b/src/Generation/GirLoader/Input/Record.cs index 032e45529..b55b29968 100644 --- a/src/Generation/GirLoader/Input/Record.cs +++ b/src/Generation/GirLoader/Input/Record.cs @@ -52,4 +52,10 @@ public class Record [XmlAttribute("foreign")] public bool Foreign; + + [XmlAttribute("copy-function")] + public string? CopyFunction { get; set; } + + [XmlAttribute("free-function")] + public string? FreeFunction { get; set; } } diff --git a/src/Generation/GirLoader/Input/Union.cs b/src/Generation/GirLoader/Input/Union.cs index 4b1ad3565..c21f2e223 100644 --- a/src/Generation/GirLoader/Input/Union.cs +++ b/src/Generation/GirLoader/Input/Union.cs @@ -37,4 +37,10 @@ public class Union [XmlAttribute("introspectable")] public bool Introspectable = true; + + [XmlAttribute("copy-function")] + public string? CopyFunction { get; set; } + + [XmlAttribute("free-function")] + public string? FreeFunction { get; set; } } diff --git a/src/Generation/GirLoader/Output/Record.GirModel.cs b/src/Generation/GirLoader/Output/Record.GirModel.cs index 3f2c28e35..d12181fcc 100644 --- a/src/Generation/GirLoader/Output/Record.GirModel.cs +++ b/src/Generation/GirLoader/Output/Record.GirModel.cs @@ -5,6 +5,8 @@ namespace GirLoader.Output; public partial class Record : GirModel.Record { GirModel.Function? GirModel.Record.TypeFunction => GetTypeFunction; + GirModel.Method? GirModel.Record.CopyFunction => CopyFunction; + GirModel.Method? GirModel.Record.FreeFunction => FreeFunction; IEnumerable GirModel.Record.Functions => Functions; IEnumerable GirModel.Record.Methods => Methods; IEnumerable GirModel.Record.Constructors => Constructors; diff --git a/src/Generation/GirLoader/Output/Record.cs b/src/Generation/GirLoader/Output/Record.cs index 59c998449..8cc2ea4af 100644 --- a/src/Generation/GirLoader/Output/Record.cs +++ b/src/Generation/GirLoader/Output/Record.cs @@ -23,8 +23,10 @@ public partial class Record : ComplexType, ShadowableProvider public bool Foreign { get; } public bool Opaque { get; } public bool Pointer { get; } + public Method? CopyFunction { get; } + public Method? FreeFunction { get; } - public Record(Repository repository, string? cType, string name, TypeReference? gLibClassStructFor, IEnumerable methods, IEnumerable functions, Function? getTypeFunction, IEnumerable fields, bool disguised, IEnumerable constructors, bool introspectable, bool foreign, bool opaque, bool pointer) : base(repository, cType, name) + public Record(Repository repository, string? cType, string name, TypeReference? gLibClassStructFor, IEnumerable methods, IEnumerable functions, Function? getTypeFunction, IEnumerable fields, bool disguised, IEnumerable constructors, bool introspectable, bool foreign, bool opaque, bool pointer, Method? copyFunction, Method? freeFunction) : base(repository, cType, name) { GLibClassStructFor = gLibClassStructFor; GetTypeFunction = getTypeFunction; @@ -34,6 +36,9 @@ public Record(Repository repository, string? cType, string name, TypeReference? Opaque = opaque; Pointer = pointer; + CopyFunction = copyFunction; + FreeFunction = freeFunction; + this._constructors = constructors.ToList(); this._methods = methods.ToList(); this._functions = functions.ToList(); diff --git a/src/Generation/GirLoader/Output/RecordFactory.cs b/src/Generation/GirLoader/Output/RecordFactory.cs index 4e2bf7894..24630c5fb 100644 --- a/src/Generation/GirLoader/Output/RecordFactory.cs +++ b/src/Generation/GirLoader/Output/RecordFactory.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; namespace GirLoader.Output; @@ -30,12 +31,14 @@ public Record Create(Input.Record record, Repository repository) _ => null }; + var methods = _methodFactory.Create(record.Methods); + var newRecord = new Record( repository: repository, cType: record.CType, name: record.Name, gLibClassStructFor: GetGLibClassStructFor(record.GLibIsGTypeStructFor, repository.Namespace), - methods: _methodFactory.Create(record.Methods), + methods: methods, functions: _functionFactory.Create(record.Functions, repository), getTypeFunction: getTypeFunction, fields: _fieldFactory.Create(record.Fields, repository), @@ -44,7 +47,9 @@ public Record Create(Input.Record record, Repository repository) introspectable: record.Introspectable, foreign: record.Foreign, opaque: record.Opaque, - pointer: record.Pointer + pointer: record.Pointer, + copyFunction: methods.FirstOrDefault(x => x.Identifier == record.CopyFunction), + freeFunction: methods.FirstOrDefault(x => x.Identifier == record.FreeFunction) ); if (getTypeFunction is not null) diff --git a/src/Generation/GirLoader/Output/Union.GirModel.cs b/src/Generation/GirLoader/Output/Union.GirModel.cs index 65906b3dd..8d907859d 100644 --- a/src/Generation/GirLoader/Output/Union.GirModel.cs +++ b/src/Generation/GirLoader/Output/Union.GirModel.cs @@ -5,6 +5,8 @@ namespace GirLoader.Output; public partial class Union : GirModel.Union { GirModel.Function? GirModel.Union.TypeFunction => GetTypeFunction; + GirModel.Method? GirModel.Union.CopyFunction => CopyFunction; + GirModel.Method? GirModel.Union.FreeFunction => FreeFunction; IEnumerable GirModel.Union.Functions => Functions; IEnumerable GirModel.Union.Methods => Methods; IEnumerable GirModel.Union.Constructors => Constructors; diff --git a/src/Generation/GirLoader/Output/Union.cs b/src/Generation/GirLoader/Output/Union.cs index e88a4b6e4..a5c3d6442 100644 --- a/src/Generation/GirLoader/Output/Union.cs +++ b/src/Generation/GirLoader/Output/Union.cs @@ -18,13 +18,18 @@ public partial class Union : ComplexType public IEnumerable Constructors => _constructors; public IEnumerable Functions => _functions; public bool Introspectable { get; } + public Method? CopyFunction { get; } + public Method? FreeFunction { get; } - public Union(Repository repository, string? cType, string name, IEnumerable methods, IEnumerable functions, Function? getTypeFunction, IEnumerable fields, bool disguised, IEnumerable constructors, bool introspectable) : base(repository, cType, name) + public Union(Repository repository, string? cType, string name, IEnumerable methods, IEnumerable functions, Function? getTypeFunction, IEnumerable fields, bool disguised, IEnumerable constructors, bool introspectable, Method? copyFunction, Method? freeFunction) : base(repository, cType, name) { GetTypeFunction = getTypeFunction; Disguised = disguised; Introspectable = introspectable; + CopyFunction = copyFunction; + FreeFunction = freeFunction; + this._constructors = constructors.ToList(); this._methods = methods.ToList(); this._functions = functions.ToList(); diff --git a/src/Generation/GirLoader/Output/UnionFactory.cs b/src/Generation/GirLoader/Output/UnionFactory.cs index aa293e1eb..d625ddf20 100644 --- a/src/Generation/GirLoader/Output/UnionFactory.cs +++ b/src/Generation/GirLoader/Output/UnionFactory.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using OneOf.Types; namespace GirLoader.Output; @@ -29,17 +30,21 @@ public Union Create(Input.Union union, Repository repository) _ => null }; + var methods = _methodFactory.Create(union.Methods); + var newUnion = new Union( repository: repository, cType: union.CType, name: union.Name, - methods: _methodFactory.Create(union.Methods), + methods: methods, functions: _functionFactory.Create(union.Functions, repository), getTypeFunction: getTypeFunction, fields: _fieldFactory.Create(union.Fields, repository), disguised: union.Disguised, constructors: _constructorFactory.Create(union.Constructors), - introspectable: union.Introspectable + introspectable: union.Introspectable, + copyFunction: methods.FirstOrDefault(x => x.Identifier == union.CopyFunction), + freeFunction: methods.FirstOrDefault(x => x.Identifier == union.FreeFunction) ); if (getTypeFunction is not null) diff --git a/src/Generation/GirLoader/PlatformSupport/Records/Record.GirModel.cs b/src/Generation/GirLoader/PlatformSupport/Records/Record.GirModel.cs index 44034d8d4..3534b6ea6 100644 --- a/src/Generation/GirLoader/PlatformSupport/Records/Record.GirModel.cs +++ b/src/Generation/GirLoader/PlatformSupport/Records/Record.GirModel.cs @@ -8,6 +8,8 @@ public partial class Record : GirModel.Record GirModel.Namespace ComplexType.Namespace => _record.Namespace; string ComplexType.Name => _record.Name; GirModel.Function? GirModel.Record.TypeFunction => _record.TypeFunction; + GirModel.Method? GirModel.Record.CopyFunction => _record.CopyFunction; + GirModel.Method? GirModel.Record.FreeFunction => _record.FreeFunction; IEnumerable GirModel.Record.Functions => _record.Functions; IEnumerable GirModel.Record.Methods => _record.Methods; IEnumerable GirModel.Record.Constructors => _record.Constructors; diff --git a/src/Generation/GirLoader/PlatformSupport/Unions/Union.GirModel.cs b/src/Generation/GirLoader/PlatformSupport/Unions/Union.GirModel.cs index 352c6e83f..cf4b48947 100644 --- a/src/Generation/GirLoader/PlatformSupport/Unions/Union.GirModel.cs +++ b/src/Generation/GirLoader/PlatformSupport/Unions/Union.GirModel.cs @@ -8,6 +8,8 @@ public partial class Union : GirModel.Union GirModel.Namespace ComplexType.Namespace => _union.Namespace; string ComplexType.Name => _union.Name; GirModel.Function? GirModel.Union.TypeFunction => _union.TypeFunction; + GirModel.Method? GirModel.Union.CopyFunction => _union.CopyFunction; + GirModel.Method? GirModel.Union.FreeFunction => _union.FreeFunction; IEnumerable GirModel.Union.Functions => _union.Functions; IEnumerable GirModel.Union.Methods => _union.Methods; IEnumerable GirModel.Union.Constructors => _union.Constructors; diff --git a/src/Generation/GirModel/Record.cs b/src/Generation/GirModel/Record.cs index 876936957..8958e5036 100644 --- a/src/Generation/GirModel/Record.cs +++ b/src/Generation/GirModel/Record.cs @@ -5,6 +5,8 @@ namespace GirModel; public interface Record : ComplexType { Function? TypeFunction { get; } + Method? CopyFunction { get; } + Method? FreeFunction { get; } IEnumerable Functions { get; } IEnumerable Methods { get; } IEnumerable Constructors { get; } diff --git a/src/Generation/GirModel/Union.cs b/src/Generation/GirModel/Union.cs index 9c4ad3744..d71787105 100644 --- a/src/Generation/GirModel/Union.cs +++ b/src/Generation/GirModel/Union.cs @@ -5,6 +5,8 @@ namespace GirModel; public interface Union : ComplexType { Function? TypeFunction { get; } + Method? CopyFunction { get; } + Method? FreeFunction { get; } IEnumerable Functions { get; } IEnumerable Methods { get; } IEnumerable Constructors { get; } From 295bbcaa416ea5f72bde3a180b7e134a8bae97e0 Mon Sep 17 00:00:00 2001 From: badcel <1218031+badcel@users.noreply.github.com> Date: Sat, 8 Jun 2024 21:32:04 +0200 Subject: [PATCH 2/2] Generator: Use Copy/Free func for untyped record handles --- src/Generation/Generator/Model/Method.cs | 10 +++ .../Internal/OpaqueUntypedRecordHandle.cs | 77 ++++++++++++++++--- .../Renderer/Public/OpaqueUntypedRecord.cs | 25 +++++- .../OpaqueUntypedRecordTesterHandle.cs | 37 --------- .../OpaqueUntypedRecordTest.cs | 7 ++ 5 files changed, 107 insertions(+), 49 deletions(-) delete mode 100644 src/Libs/GirTest-0.1/Internal/OpaqueUntypedRecordTesterHandle.cs diff --git a/src/Generation/Generator/Model/Method.cs b/src/Generation/Generator/Model/Method.cs index 55dfb8b81..12a710577 100644 --- a/src/Generation/Generator/Model/Method.cs +++ b/src/Generation/Generator/Model/Method.cs @@ -74,4 +74,14 @@ internal static void SetImplementExplicitly(GirModel.Method method) ImplementExplicitly.Add(method); } } + + public static bool IsValidCopyFunction(GirModel.Method method) + { + return !method.Parameters.Any() && method.ReturnType.IsPointer; + } + + public static bool IsValidFreeFunction(GirModel.Method method) + { + return !method.Parameters.Any() && method.ReturnType.AnyType.TryPickT0(out var type, out _) && type is GirModel.Void; + } } diff --git a/src/Generation/Generator/Renderer/Internal/OpaqueUntypedRecordHandle.cs b/src/Generation/Generator/Renderer/Internal/OpaqueUntypedRecordHandle.cs index 745dbfd53..9c4a10d5a 100644 --- a/src/Generation/Generator/Renderer/Internal/OpaqueUntypedRecordHandle.cs +++ b/src/Generation/Generator/Renderer/Internal/OpaqueUntypedRecordHandle.cs @@ -112,6 +112,69 @@ public class {ownedHandleTypeName} : {typeName} }}"; } + private static string RenderCopyFunctions(GirModel.Record record) + { + var unownedHandleTypeName = Model.OpaqueUntypedRecord.GetInternalUnownedHandle(record); + var ownedHandleTypeName = Model.OpaqueUntypedRecord.GetInternalOwnedHandle(record); + + return record.CopyFunction is null || !Method.IsValidCopyFunction(record.CopyFunction) + ? $""" + public partial {ownedHandleTypeName} OwnedCopy(); + public partial {unownedHandleTypeName} UnownedCopy(); + """ + : $$""" + [DllImport(ImportResolver.Library, EntryPoint = "{{record.CopyFunction}}")] + protected static extern IntPtr Copy(IntPtr handle); + + public {{ownedHandleTypeName}} OwnedCopy() + { + return new {{ownedHandleTypeName}}(Copy(handle)); + } + + public {{unownedHandleTypeName}} UnownedCopy() + { + return new {{unownedHandleTypeName}}(Copy(handle)); + } + """; + } + + private static string RenderFromUnowned(GirModel.Record record) + { + var ownedHandleTypeName = Model.OpaqueUntypedRecord.GetInternalOwnedHandle(record); + + return record.CopyFunction is null || !Method.IsValidCopyFunction(record.CopyFunction) + ? $""" + /// + /// Create a {ownedHandleTypeName} from a pointer that is assumed unowned. + /// + /// A pointer to a {record.Name} which is not owned by the runtime. + /// A {ownedHandleTypeName} + public static partial {ownedHandleTypeName} FromUnowned(IntPtr ptr); + """ + : $$""" + public static {{ownedHandleTypeName}} FromUnowned(IntPtr ptr) + { + return new {{ownedHandleTypeName}}(Copy(ptr)); + } + """; + } + + private static string RenderReleaseHandle(GirModel.Record record) + { + return record.FreeFunction is null || !Method.IsValidFreeFunction(record.FreeFunction) + ? "protected override partial bool ReleaseHandle();" + : $$""" + [DllImport(ImportResolver.Library, EntryPoint = "{{record.FreeFunction}}")] + private static extern void Free(IntPtr handle); + + protected override bool ReleaseHandle() + { + Free(handle); + return true; + } + """; + } + private static string StandardHandle(GirModel.Record record) { var typeName = Model.OpaqueUntypedRecord.GetInternalHandle(record); @@ -136,8 +199,7 @@ public abstract partial class {typeName} : SafeHandle protected {typeName}(bool ownsHandle) : base(IntPtr.Zero, ownsHandle) {{ }} - public partial {ownedHandleTypeName} OwnedCopy(); - public partial {unownedHandleTypeName} UnownedCopy(); + {RenderCopyFunctions(record)} }} public class {unownedHandleTypeName} : {typeName} @@ -178,15 +240,8 @@ public partial class {ownedHandleTypeName} : {typeName} {{ SetHandle(ptr); }} - - /// - /// Create a {ownedHandleTypeName} from a pointer that is assumed unowned. - /// - /// A pointer to a {record.Name} which is not owned by the runtime. - /// A {ownedHandleTypeName} - public static partial {ownedHandleTypeName} FromUnowned(IntPtr ptr); - - protected override partial bool ReleaseHandle(); + {RenderFromUnowned(record)} + {RenderReleaseHandle(record)} }}"; } } diff --git a/src/Generation/Generator/Renderer/Public/OpaqueUntypedRecord.cs b/src/Generation/Generator/Renderer/Public/OpaqueUntypedRecord.cs index 11352ad4d..bcfc722e2 100644 --- a/src/Generation/Generator/Renderer/Public/OpaqueUntypedRecord.cs +++ b/src/Generation/Generator/Renderer/Public/OpaqueUntypedRecord.cs @@ -24,7 +24,7 @@ namespace {Namespace.GetPublicName(record.Namespace)}; // AUTOGENERATED FILE - DO NOT MODIFY {PlatformSupportAttribute.Render(record as GirModel.PlatformDependent)} -public sealed partial class {name} +public sealed partial class {name} {RenderIDisposableDefinition(record.FreeFunction)} {{ public {internalHandleName} Handle {{ get; }} @@ -70,6 +70,29 @@ public override int GetHashCode() {{ return Handle.GetHashCode(); }} + + {RenderIDisposableImplementation(record.FreeFunction)} }}"; } + + private static string RenderIDisposableDefinition(GirModel.Method? freeFunc) + { + if (freeFunc is null || !Method.IsValidFreeFunction(freeFunc)) + return string.Empty; + + return ": IDisposable"; + } + + private static string RenderIDisposableImplementation(GirModel.Method? freeFunc) + { + if (freeFunc is null || !Method.IsValidFreeFunction(freeFunc)) + return string.Empty; + + return """ + public void Dispose() + { + Handle.Dispose(); + } + """; + } } diff --git a/src/Libs/GirTest-0.1/Internal/OpaqueUntypedRecordTesterHandle.cs b/src/Libs/GirTest-0.1/Internal/OpaqueUntypedRecordTesterHandle.cs deleted file mode 100644 index 27dd45c89..000000000 --- a/src/Libs/GirTest-0.1/Internal/OpaqueUntypedRecordTesterHandle.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace GirTest.Internal; - -public abstract partial class OpaqueUntypedRecordTesterHandle -{ - [DllImport(ImportResolver.Library, EntryPoint = "girtest_opaque_untyped_record_tester_ref")] - protected static extern IntPtr Ref(IntPtr queue); - - public partial OpaqueUntypedRecordTesterOwnedHandle OwnedCopy() - { - return new OpaqueUntypedRecordTesterOwnedHandle(Ref(handle)); - } - - public partial OpaqueUntypedRecordTesterUnownedHandle UnownedCopy() - { - return new OpaqueUntypedRecordTesterUnownedHandle(Ref(handle)); - } -} - -public partial class OpaqueUntypedRecordTesterOwnedHandle -{ - [DllImport(ImportResolver.Library, EntryPoint = "girtest_opaque_untyped_record_tester_unref")] - private static extern void Unref(IntPtr queue); - - public static partial OpaqueUntypedRecordTesterOwnedHandle FromUnowned(IntPtr ptr) - { - return new OpaqueUntypedRecordTesterOwnedHandle(Ref(ptr)); - } - - protected override partial bool ReleaseHandle() - { - Unref(handle); - return true; - } -} diff --git a/src/Tests/Libs/GirTest-0.1.Tests/OpaqueUntypedRecordTest.cs b/src/Tests/Libs/GirTest-0.1.Tests/OpaqueUntypedRecordTest.cs index a1a5ba54a..74d0ae886 100644 --- a/src/Tests/Libs/GirTest-0.1.Tests/OpaqueUntypedRecordTest.cs +++ b/src/Tests/Libs/GirTest-0.1.Tests/OpaqueUntypedRecordTest.cs @@ -7,6 +7,13 @@ namespace GirTest.Tests; [TestClass, TestCategory("BindingTest")] public class OpaqueUntypedRecordTest : Test { + [TestMethod] + public void ImplementsIDisposable() + { + var recordTester = OpaqueUntypedRecordTester.New(); + recordTester.Dispose(); + } + [TestMethod] public void SupportsConstructorTransferFull() {