From 8992974796c660d80bcc1e7d75e0a05d7e8fd874 Mon Sep 17 00:00:00 2001 From: badcel <1218031+badcel@users.noreply.github.com> Date: Sat, 6 Jan 2024 22:25:28 +0100 Subject: [PATCH] TypedRecord: Add field access --- .../Renderer/Internal/TypedRecordHandle.cs | 6 ++-- .../Public/Field/Converter/Bitfield.cs | 26 ++++++++++++++ .../Public/Field/Converter/Enumeration.cs | 26 ++++++++++++++ .../Field/Converter/PrimitiveValueType.cs | 24 +++++++++++++ .../Renderer/Public/Field/Converter/String.cs | 19 ++++++++++ .../Renderer/Public/Field/FieldConverter.cs | 7 ++++ .../Generator/Renderer/Public/Field/Fields.cs | 23 ++++++++++++ .../Renderer/Public/Field/RenderableField.cs | 3 ++ .../Generator/Renderer/Public/TypedRecord.cs | 35 +++++++++++++++++++ .../Libs/GirTest-0.1.Tests/TypedRecordTest.cs | 11 ++++++ 10 files changed, 176 insertions(+), 4 deletions(-) create mode 100644 src/Generation/Generator/Renderer/Public/Field/Converter/Bitfield.cs create mode 100644 src/Generation/Generator/Renderer/Public/Field/Converter/Enumeration.cs create mode 100644 src/Generation/Generator/Renderer/Public/Field/Converter/PrimitiveValueType.cs create mode 100644 src/Generation/Generator/Renderer/Public/Field/Converter/String.cs create mode 100644 src/Generation/Generator/Renderer/Public/Field/FieldConverter.cs create mode 100644 src/Generation/Generator/Renderer/Public/Field/Fields.cs create mode 100644 src/Generation/Generator/Renderer/Public/Field/RenderableField.cs diff --git a/src/Generation/Generator/Renderer/Internal/TypedRecordHandle.cs b/src/Generation/Generator/Renderer/Internal/TypedRecordHandle.cs index aa870df0b..256974900 100644 --- a/src/Generation/Generator/Renderer/Internal/TypedRecordHandle.cs +++ b/src/Generation/Generator/Renderer/Internal/TypedRecordHandle.cs @@ -252,8 +252,7 @@ private static string RenderFieldGetter(GirModel.Record record, GirModel.Field f if (IsClosed || IsInvalid) throw new InvalidOperationException(""Handle is closed or invalid""); - var data = Unsafe.AsRef<{dataName}>((void*)handle); - return data.{renderableField.Name}; + return Unsafe.AsRef<{dataName}>((void*)handle).{renderableField.Name}; }}"; } @@ -266,8 +265,7 @@ private static string RenderFieldSetter(GirModel.Record record, GirModel.Field f if (IsClosed || IsInvalid) throw new InvalidOperationException(""Handle is closed or invalid""); - var data = Unsafe.AsRef<{dataName}>((void*)handle); - data.{renderableField.Name} = value; + Unsafe.AsRef<{dataName}>((void*)handle).{renderableField.Name} = value; }}"; } diff --git a/src/Generation/Generator/Renderer/Public/Field/Converter/Bitfield.cs b/src/Generation/Generator/Renderer/Public/Field/Converter/Bitfield.cs new file mode 100644 index 000000000..fe3e77f8b --- /dev/null +++ b/src/Generation/Generator/Renderer/Public/Field/Converter/Bitfield.cs @@ -0,0 +1,26 @@ +namespace Generator.Renderer.Public.Field; + +internal class Bitfield : FieldConverter +{ + public bool Supports(GirModel.Field field) + { + return field.AnyTypeOrCallback.TryPickT0(out var anyType, out _) && anyType.Is(); + } + + public RenderableField Convert(GirModel.Field field) + { + return new RenderableField( + Name: Model.Field.GetName(field), + NullableTypeName: GetNullableTypeName(field) + ); + } + + private static string GetNullableTypeName(GirModel.Field field) + { + var type = (GirModel.Bitfield) field.AnyTypeOrCallback.AsT0.AsT0; + return field.IsPointer + ? Model.Type.Pointer + : Model.ComplexType.GetFullyQualified(type); + } +} + diff --git a/src/Generation/Generator/Renderer/Public/Field/Converter/Enumeration.cs b/src/Generation/Generator/Renderer/Public/Field/Converter/Enumeration.cs new file mode 100644 index 000000000..97432acaa --- /dev/null +++ b/src/Generation/Generator/Renderer/Public/Field/Converter/Enumeration.cs @@ -0,0 +1,26 @@ +namespace Generator.Renderer.Public.Field; + +internal class Enumeration : FieldConverter +{ + public bool Supports(GirModel.Field field) + { + return field.AnyTypeOrCallback.TryPickT0(out var anyType, out _) && anyType.Is(); + } + + public RenderableField Convert(GirModel.Field field) + { + return new RenderableField( + Name: Model.Field.GetName(field), + NullableTypeName: GetNullableTypeName(field) + ); + } + + private static string GetNullableTypeName(GirModel.Field field) + { + var type = (GirModel.Enumeration) field.AnyTypeOrCallback.AsT0.AsT0; + return field.IsPointer + ? Model.Type.Pointer + : Model.ComplexType.GetFullyQualified(type); + } + +} diff --git a/src/Generation/Generator/Renderer/Public/Field/Converter/PrimitiveValueType.cs b/src/Generation/Generator/Renderer/Public/Field/Converter/PrimitiveValueType.cs new file mode 100644 index 000000000..968abd12e --- /dev/null +++ b/src/Generation/Generator/Renderer/Public/Field/Converter/PrimitiveValueType.cs @@ -0,0 +1,24 @@ +namespace Generator.Renderer.Public.Field; + +internal class PrimitiveValueType : FieldConverter +{ + public bool Supports(GirModel.Field field) + { + return field.AnyTypeOrCallback.TryPickT0(out var anyType, out _) && anyType.Is(); + } + + public RenderableField Convert(GirModel.Field field) + { + return new RenderableField( + Name: Model.Field.GetName(field), + NullableTypeName: GetNullableTypeName(field) + ); + } + + private static string GetNullableTypeName(GirModel.Field field) + { + return field.IsPointer + ? Model.Type.Pointer + : Model.Type.GetName(field.AnyTypeOrCallback.AsT0.AsT0); + } +} diff --git a/src/Generation/Generator/Renderer/Public/Field/Converter/String.cs b/src/Generation/Generator/Renderer/Public/Field/Converter/String.cs new file mode 100644 index 000000000..65c6f10ef --- /dev/null +++ b/src/Generation/Generator/Renderer/Public/Field/Converter/String.cs @@ -0,0 +1,19 @@ +using Generator.Model; + +namespace Generator.Renderer.Public.Field; + +internal class String : FieldConverter +{ + public bool Supports(GirModel.Field field) + { + return field.AnyTypeOrCallback.TryPickT0(out var anyType, out _) && anyType.Is(); + } + + public RenderableField Convert(GirModel.Field field) + { + return new RenderableField( + Name: Model.Field.GetName(field), + NullableTypeName: Type.GetName(field.AnyTypeOrCallback.AsT0.AsT0) + ); + } +} diff --git a/src/Generation/Generator/Renderer/Public/Field/FieldConverter.cs b/src/Generation/Generator/Renderer/Public/Field/FieldConverter.cs new file mode 100644 index 000000000..0874cdc3b --- /dev/null +++ b/src/Generation/Generator/Renderer/Public/Field/FieldConverter.cs @@ -0,0 +1,7 @@ +namespace Generator.Renderer.Public.Field; + +public interface FieldConverter +{ + bool Supports(GirModel.Field field); + RenderableField Convert(GirModel.Field field); +} diff --git a/src/Generation/Generator/Renderer/Public/Field/Fields.cs b/src/Generation/Generator/Renderer/Public/Field/Fields.cs new file mode 100644 index 000000000..c21d74198 --- /dev/null +++ b/src/Generation/Generator/Renderer/Public/Field/Fields.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; + +namespace Generator.Renderer.Public; + +internal static class Fields +{ + private static readonly List Converters = new() + { + new Field.Bitfield(), + new Field.Enumeration(), + new Field.PrimitiveValueType(), + new Field.String(), + }; + + public static Field.RenderableField GetRenderableField(GirModel.Field field) + { + foreach (var converter in Converters) + if (converter.Supports(field)) + return converter.Convert(field); + + throw new System.Exception($"Internal field \"{field.Name}\" of type {field.AnyTypeOrCallback} can not be rendered"); + } +} diff --git a/src/Generation/Generator/Renderer/Public/Field/RenderableField.cs b/src/Generation/Generator/Renderer/Public/Field/RenderableField.cs new file mode 100644 index 000000000..70e7751f7 --- /dev/null +++ b/src/Generation/Generator/Renderer/Public/Field/RenderableField.cs @@ -0,0 +1,3 @@ +namespace Generator.Renderer.Public.Field; + +public record RenderableField(string Name, string NullableTypeName); diff --git a/src/Generation/Generator/Renderer/Public/TypedRecord.cs b/src/Generation/Generator/Renderer/Public/TypedRecord.cs index f8c3b81e2..d6ffcd3e5 100644 --- a/src/Generation/Generator/Renderer/Public/TypedRecord.cs +++ b/src/Generation/Generator/Renderer/Public/TypedRecord.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Text; using Generator.Model; namespace Generator.Renderer.Public; @@ -49,6 +50,10 @@ public partial class {name} {FunctionRenderer.Render(record.TypeFunction)} + {record.Fields + .Select(f => RenderField(record, f)) + .Join(Environment.NewLine)} + {record.Functions .Select(FunctionRenderer.Render) .Join(Environment.NewLine)} @@ -59,4 +64,34 @@ public partial class {name} .Join(Environment.NewLine)} }}"; } + + private static string RenderField(GirModel.Record record, GirModel.Field field) + { + try + { + var renderableField = Fields.GetRenderableField(field); + + if (field is { IsReadable: false, IsWritable: false } || field.IsPrivate) + return string.Empty; + + var result = new StringBuilder(); + + result.AppendLine($"public {renderableField.NullableTypeName} {renderableField.Name} {{"); + + if (field.IsReadable) + result.AppendLine($"get => Handle.Get{renderableField.Name}();"); + + if (field.IsWritable) + result.AppendLine($"set => Handle.Set{renderableField.Name}(value);"); + + result.AppendLine("}"); + + return result.ToString(); + } + catch (Exception ex) + { + Log.Warning($"Did not render typed record {record.Name} field {field.Name}: {ex.Message}"); + return string.Empty; + } + } } diff --git a/src/Tests/Libs/GirTest-0.1.Tests/TypedRecordTest.cs b/src/Tests/Libs/GirTest-0.1.Tests/TypedRecordTest.cs index 22891d5e9..3555f2d93 100644 --- a/src/Tests/Libs/GirTest-0.1.Tests/TypedRecordTest.cs +++ b/src/Tests/Libs/GirTest-0.1.Tests/TypedRecordTest.cs @@ -317,4 +317,15 @@ void Callback(out TypedRecordTester? recordTester) var result = TypedRecordTester.RunCallbackCreateNullableFullOwnershipTransferOut(Callback); result!.Handle.DangerousGetHandle().Should().Be(instance.Handle.DangerousGetHandle()); } + + [TestMethod] + public void SupportsPrimitiveValueTypeField() + { + var instance = TypedRecordTester.New(); + instance.RefCount.Should().Be(1); + instance.RefCount = 2; + instance.RefCount.Should().Be(2); + instance.RefCount = 1; + instance.RefCount.Should().Be(1); + } }