Skip to content

Commit

Permalink
Generator: Support opaque typed records with copy / free annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
badcel committed Jul 19, 2024
1 parent 7c1b5a8 commit ba6ce6b
Show file tree
Hide file tree
Showing 11 changed files with 481 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ 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;
Expand All @@ -29,15 +28,17 @@ public abstract class {typeName} : SafeHandle, IEquatable<{typeName}>
protected {typeName}(bool ownsHandle) : base(IntPtr.Zero, ownsHandle) {{ }}
{RenderCopyFunction(record)}
public {ownedHandleTypeName} OwnedCopy()
{{
var ptr = GObject.Internal.Functions.BoxedCopy({getGType}, handle);
{RenderCopyStatement(record, "ptr", "handle")}
return new {ownedHandleTypeName}(ptr);
}}
public {unownedHandleTypeName} UnownedCopy()
{{
var ptr = GObject.Internal.Functions.BoxedCopy({getGType}, handle);
{RenderCopyStatement(record, "ptr", "handle")}
return new {unownedHandleTypeName}(ptr);
}}
Expand Down Expand Up @@ -102,6 +103,8 @@ public class {ownedHandleTypeName} : {typeName}
SetHandle(ptr);
}}
{RenderFreeFunction(record)}
/// <summary>
/// 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.
Expand All @@ -110,15 +113,53 @@ public class {ownedHandleTypeName} : {typeName}
/// <returns>A {ownedHandleTypeName}</returns>
public static {ownedHandleTypeName} FromUnowned(IntPtr ptr)
{{
var ownedPtr = GObject.Internal.Functions.BoxedCopy({getGType}, ptr);
return new {ownedHandleTypeName}(ownedPtr);
{RenderCopyStatement(record, "ownedPtr", "ptr")}
return new {ownedHandleTypeName}(ownedPtr);
}}
protected override bool ReleaseHandle()
{{
GObject.Internal.Functions.BoxedFree({getGType}, handle);
return true;
{RenderFreeStatement(record, "handle")}
return true;
}}
}}";
}

private static string RenderCopyFunction(GirModel.Record record)
{
return record.CopyFunction is null || !Method.IsValidCopyFunction(record.CopyFunction)
? string.Empty
: $"""
[DllImport(ImportResolver.Library, EntryPoint = "{record.CopyFunction}")]
protected static extern IntPtr Copy(IntPtr handle);
""";
}

private static string RenderFreeFunction(GirModel.Record record)
{
return record.FreeFunction is null || !Method.IsValidFreeFunction(record.FreeFunction)
? string.Empty
: $"""
[DllImport(ImportResolver.Library, EntryPoint = "{record.FreeFunction}")]
private static extern void Free(IntPtr handle);
""";
}

private static string RenderCopyStatement(GirModel.Record record, string resultVariable, string parameterVariable)
{
var getGType = $"{Model.OpaqueTypedRecord.GetFullyQualifiedInternalClassName(record)}.{Function.GetGType}()";

return record.CopyFunction is null || !Method.IsValidCopyFunction(record.CopyFunction)
? $"var {resultVariable} = GObject.Internal.Functions.BoxedCopy({getGType}, {parameterVariable});"
: $"var {resultVariable} = Copy({parameterVariable});";
}

private static string RenderFreeStatement(GirModel.Record record, string parameterVariable)
{
var getGType = $"{Model.OpaqueTypedRecord.GetFullyQualifiedInternalClassName(record)}.{Function.GetGType}()";

return record.FreeFunction is null || !Method.IsValidFreeFunction(record.FreeFunction)
? $"GObject.Internal.Functions.BoxedFree({getGType}, {parameterVariable});"
: $"Free({parameterVariable});";
}
}
16 changes: 15 additions & 1 deletion src/Generation/Generator/Renderer/Public/OpaqueTypedRecord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ internal static class OpaqueTypedRecord
{
public static string Render(GirModel.Record record)
{
if (record.FreeFunction is null)
Log.Information($"Record {record.Name}: Has no free-func annotation. Define it upstream to improve performance for this type.");

if (record.CopyFunction is null)
Log.Information($"Record {record.Name}: Has no copy-func annotation. Define it upstream to improve performance for this type.");

var name = Model.OpaqueTypedRecord.GetPublicClassName(record);
var internalHandleName = Model.OpaqueTypedRecord.GetFullyQuallifiedOwnedHandle(record);

Expand All @@ -24,7 +30,7 @@ namespace {Namespace.GetPublicName(record.Namespace)};
// AUTOGENERATED FILE - DO NOT MODIFY
{PlatformSupportAttribute.Render(record as GirModel.PlatformDependent)}
public sealed partial class {name} : GLib.BoxedRecord, IEquatable<{name}>
public sealed partial class {name} : GLib.BoxedRecord, IEquatable<{name}>, IDisposable
{{
public {internalHandleName} Handle {{ get; }}
Expand Down Expand Up @@ -83,6 +89,14 @@ public override int GetHashCode()
{{
return Handle.GetHashCode();
}}
partial void OnDispose();
public void Dispose()
{{
OnDispose();
Handle.Dispose();
}}
}}";
}
}
6 changes: 2 additions & 4 deletions src/Libs/GLib-2.0/Public/Bytes.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
using System;
using System.Runtime.InteropServices;

namespace GLib;

public sealed partial class Bytes : IDisposable
public sealed partial class Bytes
{
private long _size;

Expand All @@ -13,9 +12,8 @@ partial void Initialize()
GC.AddMemoryPressure(_size);
}

public void Dispose()
partial void OnDispose()
{
Handle.Dispose();
GC.RemoveMemoryPressure(_size);
}
}
11 changes: 0 additions & 11 deletions src/Libs/GLib-2.0/Public/Dir.cs

This file was deleted.

12 changes: 2 additions & 10 deletions src/Libs/GLib-2.0/Public/VariantType.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
using System;
using System.Runtime.InteropServices;
namespace GLib;

namespace GLib;

public partial class VariantType : IDisposable
public partial class VariantType
{
public static readonly VariantType String = New("s");
public static readonly VariantType Variant = New("v");

public void Dispose()
{
Handle.Dispose();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
#include "girtest-opaque-typed-record-copy-annotation-tester.h"

/**
* GirTestOpaqueTypedRecordCopyAnnotationTester:
* (copy-func girtest_opaque_typed_record_copy_annotation_tester_ref)
* (free-func girtest_opaque_typed_record_copy_annotation_tester_unref)
*
* Just an opaque record.
*/
struct _GirTestOpaqueTypedRecordCopyAnnotationTester
{
int ref_count;
};

G_DEFINE_BOXED_TYPE (GirTestOpaqueTypedRecordCopyAnnotationTester, girtest_opaque_typed_record_copy_annotation_tester, girtest_opaque_typed_record_copy_annotation_tester_ref, girtest_opaque_typed_record_copy_annotation_tester_unref)

/**
* girtest_opaque_typed_record_copy_annotation_tester_new: (constructor)
*
* Returns: (transfer full): a new `GirTestOpaqueTypedRecordCopyAnnotationTester`
**/
GirTestOpaqueTypedRecordCopyAnnotationTester *
girtest_opaque_typed_record_copy_annotation_tester_new ()
{
GirTestOpaqueTypedRecordCopyAnnotationTester *result;
result = g_new0 (GirTestOpaqueTypedRecordCopyAnnotationTester, 1);
result->ref_count = 1;
return result;
}

/**
* girtest_opaque_typed_record_copy_annotation_tester_ref:
* @self: a `GirTestRecordTester`
*
* Increments the reference count on `data`.
*
* Returns: (transfer full): the data.
**/
GirTestOpaqueTypedRecordCopyAnnotationTester *
girtest_opaque_typed_record_copy_annotation_tester_ref (GirTestOpaqueTypedRecordCopyAnnotationTester *self)
{
g_return_val_if_fail (self != NULL, NULL);
self->ref_count += 1;
return self;
}

/**
* girtest_opaque_typed_record_copy_annotation_tester_mirror:
* @data: a `GirTestRecordTester`
*
* Mirrors the given data as the return value. Ownership is not transferred.
*
* Returns: (transfer none): the mirrored data.
**/
GirTestOpaqueTypedRecordCopyAnnotationTester *
girtest_opaque_typed_record_copy_annotation_tester_mirror(GirTestOpaqueTypedRecordCopyAnnotationTester *data)
{
return data;
}

/**
* girtest_opaque_typed_record_copy_annotation_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.
**/
GirTestOpaqueTypedRecordCopyAnnotationTester *
girtest_opaque_typed_record_copy_annotation_tester_nullable_mirror(GirTestOpaqueTypedRecordCopyAnnotationTester *data, gboolean mirror)
{
if(!mirror)
return NULL;

return data;
}

/**
* girtrest_opaque_typed_record_copy_annotation_tester_unref:
* @self: (transfer full): a `GirTestOpaqueTypedRecordCopyAnnotationTester`
*
* Decrements the reference count on `data` and frees the
* data if the reference count is 0.
**/
void
girtest_opaque_typed_record_copy_annotation_tester_unref (GirTestOpaqueTypedRecordCopyAnnotationTester *self)
{
g_return_if_fail (self != NULL);

self->ref_count -= 1;
if (self->ref_count > 0)
return;

g_free (self);
}

/**
* girtest_opaque_typed_record_copy_annotation_tester_get_ref_count:
* @self: a `GirTestOpaqueTypedRecordCopyAnnotationTester`
*
* Returns: The current ref count of the opaque record.
**/
int
girtest_opaque_typed_record_copy_annotation_tester_get_ref_count(GirTestOpaqueTypedRecordCopyAnnotationTester *self)
{
g_return_val_if_fail (self != NULL, -1);
return self->ref_count;
}

/**
* girtest_opaque_typed_record_copy_annotation_tester_take_and_unref:
* @self: (transfer full): a `GirTestOpaqueTypedRecordCopyAnnotationTester`
*
* Takes ownership and decrements the reference count on `data` and frees the
* data if the reference count is 0.
**/
void
girtest_opaque_typed_record_copy_annotation_tester_take_and_unref(GirTestOpaqueTypedRecordCopyAnnotationTester *self)
{
girtest_opaque_typed_record_copy_annotation_tester_unref(self);
}

/**
* girtest_opaque_typed_record_copy_annotation_tester_take_and_unref_func:
* @dummy: Just an unused dummy value
* @data: (transfer full): a `GirTestOpaqueTypedRecordCopyAnnotationTester`
*
* Takes ownership and decrements the reference count on `data` and frees the
* data if the reference count is 0.
**/
void
girtest_opaque_typed_record_copy_annotation_tester_take_and_unref_func(int dummy, GirTestOpaqueTypedRecordCopyAnnotationTester *data)
{
girtest_opaque_typed_record_copy_annotation_tester_take_and_unref(data);
}

/**
* girtest_opaque_typed_record_copy_annotation_tester_take_and_unref_func_nullable:
* @dummy: Just an unused dummy value
* @data: (transfer full) (nullable): a `GirTestOpaqueTypedRecordCopyAnnotationTester`
*
* Takes ownership and decrements the reference count on `data` and frees the
* data if the reference count is 0.
**/
void
girtest_opaque_typed_record_copy_annotation_tester_take_and_unref_func_nullable(int dummy, GirTestOpaqueTypedRecordCopyAnnotationTester *data)
{
if(data == NULL)
return;

girtest_opaque_typed_record_copy_annotation_tester_take_and_unref(data);
}

/**
* girtest_opaque_typed_record_copy_annotation_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 GirTestOpaqueTypedRecordCopyAnnotationTester
**/
GirTestOpaqueTypedRecordCopyAnnotationTester *
girtest_opaque_typed_record_copy_annotation_tester_run_callback_return_no_ownership_transfer(GirTestCreateOpaqueTypedRecordCopyAnnotationTesterNoOwnershipTransfer callback)
{
return callback();
}

/**
* girtest_opaque_typed_record_copy_annotation_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 GirTestOpaqueTypedRecordCopyAnnotationTester
**/
GirTestOpaqueTypedRecordCopyAnnotationTester * girtest_opaque_typed_record_copy_annotation_tester_run_callback_return_no_ownership_transfer_nullable(GirTestCreateOpaqueTypedRecordCopyAnnotationTesterNoOwnershipTransferNullable callback)
{
return callback();
}

/**
* girtest_opaque_typed_record_copy_annotation_tester_run_callback_parameter_no_ownership_transfer:
* @callback: (scope call): a callback
* @data: (transfer none): A GirTestOpaqueTypedRecordCopyAnnotationTester
*
* Calls the callback and supplies the given OpaqueTypedRecordTester.
**/
void
girtest_opaque_typed_record_copy_annotation_tester_run_callback_parameter_no_ownership_transfer(GirTestGetOpaqueTypedRecordCopyAnnotationTesterNoOwnershipTransfer callback, GirTestOpaqueTypedRecordCopyAnnotationTester *data)
{
callback(data);
}

/**
* girtest_opaque_typed_record_copy_annotation_tester_run_callback_parameter_no_ownership_transfer_nullable:
* @callback: (scope call): a callback
* @data: (transfer none) (nullable): A GirTestOpaqueTypedRecordCopyAnnotationTester
*
* Calls the callback and supplies the given OpaqueTypedRecordTester.
**/
void
girtest_opaque_typed_record_copy_annotation_tester_run_callback_parameter_no_ownership_transfer_nullable(GirTestGetOpaqueTypedRecordCopyAnnotationTesterNoOwnershipTransferNullable callback, GirTestOpaqueTypedRecordCopyAnnotationTester *data)
{
callback(data);
}
Loading

0 comments on commit ba6ce6b

Please sign in to comment.