diff --git a/Generator/Extensions/TypeExtension.cs b/Generator/Extensions/TypeExtension.cs index 5da03dd9a..e7208e709 100644 --- a/Generator/Extensions/TypeExtension.cs +++ b/Generator/Extensions/TypeExtension.cs @@ -12,9 +12,10 @@ internal static string Write(this Type type, Target target, Namespace currentNam { PrimitiveType => type.Name, - // Enumerations do not have a native representation they + // Enumerations/Bitfields do not have a native representation they // always live in the managed namespace (see method GetName) Enumeration e => $"{e.Repository.Namespace.Name}.{e.Name}", + Bitfield e => $"{e.Repository.Namespace.Name}.{e.Name}", ComplexType c when !c.Repository.Namespace.IsForeignTo(currentNamespace) => c.Name, ComplexType c => $"{c.Repository.Namespace.GetName(target)}.{c.Name}", diff --git a/Generator/Services/Writer/WriterService.cs b/Generator/Services/Writer/WriterService.cs index 086fa8cd3..048e88c25 100644 --- a/Generator/Services/Writer/WriterService.cs +++ b/Generator/Services/Writer/WriterService.cs @@ -76,7 +76,7 @@ public void Write(Namespace ns, string outputDir, WriterOptions options) _writeTypesService.Write( projectName: ns.ToCanonicalName(), outputDir: outputDir, - templateName: "enum.sbntxt", + templateName: "bitfield.sbntxt", subfolder: Folder.Managed.Enums, types: ns.Bitfields, @namespace: ns diff --git a/Generator/Templates/bitfield.sbntxt b/Generator/Templates/bitfield.sbntxt new file mode 100644 index 000000000..547fa769f --- /dev/null +++ b/Generator/Templates/bitfield.sbntxt @@ -0,0 +1,13 @@ +{{~ #Bitfields are passed as ulong via the ffi ~}} +using System; + +namespace {{ namespace.name }} +{ + [Flags] + public enum {{ name }} : ulong + { + {{~ for member in members }} + {{ include 'member.sbntxt' member ~}} + {{ end }} + } +} \ No newline at end of file diff --git a/Generator/Templates/enum.sbntxt b/Generator/Templates/enum.sbntxt index 747bb811d..80313f6cb 100644 --- a/Generator/Templates/enum.sbntxt +++ b/Generator/Templates/enum.sbntxt @@ -1,14 +1,12 @@ +{{~ #Enumerations are passed as long via the ffi ~}} using System; namespace {{ namespace.name }} { - {{~ if has_flags ~}} - [Flags] - {{~ end ~}} public enum {{ name }} : long { {{~ for member in members }} - {{ include 'enum.member.sbntxt' member ~}} + {{ include 'member.sbntxt' member ~}} {{ end }} } } \ No newline at end of file diff --git a/Generator/Templates/enum.member.sbntxt b/Generator/Templates/member.sbntxt similarity index 100% rename from Generator/Templates/enum.member.sbntxt rename to Generator/Templates/member.sbntxt diff --git a/GirLoader/Input/Model/Bitfield.cs b/GirLoader/Input/Model/Bitfield.cs new file mode 100644 index 000000000..c0c385dae --- /dev/null +++ b/GirLoader/Input/Model/Bitfield.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Xml.Serialization; + +namespace GirLoader.Input.Model +{ + public class Bitfield + { + [XmlAttribute("name")] + public string? Name { get; set; } + + [XmlAttribute("type", Namespace = "http://www.gtk.org/introspection/c/1.0")] + public string? Type { get; set; } + + [XmlAttribute("type-name", Namespace = "http://www.gtk.org/introspection/glib/1.0")] + public string? TypeName { get; set; } + + [XmlElement("doc")] + public Doc? Doc { get; set; } + + [XmlElement("member")] + public List Members { get; set; } = default!; + } +} diff --git a/GirLoader/Input/Model/Namespace.cs b/GirLoader/Input/Model/Namespace.cs index 7ddf0a1a9..506be0d49 100644 --- a/GirLoader/Input/Model/Namespace.cs +++ b/GirLoader/Input/Model/Namespace.cs @@ -27,7 +27,7 @@ public class Namespace public List Interfaces { get; set; } = new(); [XmlElement("bitfield")] - public List Bitfields { get; set; } = new(); + public List Bitfields { get; set; } = new(); [XmlElement("enumeration")] public List Enumerations { get; set; } = new(); diff --git a/GirLoader/Output/Model/Bitfield.cs b/GirLoader/Output/Model/Bitfield.cs new file mode 100644 index 000000000..65988e0e5 --- /dev/null +++ b/GirLoader/Output/Model/Bitfield.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using System.Linq; +using GirLoader.Helper; + +namespace GirLoader.Output.Model +{ + public class Bitfield : ComplexType + { + public IEnumerable Members { get; } + + public Bitfield(Repository repository, CType? cType, TypeName originalName, TypeName name, IEnumerable members) : base(repository, cType, name, originalName) + { + Members = members; + } + + internal override IEnumerable GetTypeReferences() + => Members.SelectMany(x => x.GetTypeReferences()); + + internal override bool GetIsResolved() + => Members.All(x => x.GetIsResolved()); + + internal override bool Matches(TypeReference typeReference) + { + if (typeReference.SymbolNameReference is not null) + { + var namespaceOk = typeReference.SymbolNameReference.NamespaceName == Repository.Namespace.Name + || typeReference.SymbolNameReference.NamespaceName == null; + + return namespaceOk && typeReference.SymbolNameReference.SymbolName == OriginalName; + } + + if (typeReference.CTypeReference is not null) + return typeReference.CTypeReference.CType == CType; + + return false; + } + } +} diff --git a/GirLoader/Output/Model/BitfieldFactory.cs b/GirLoader/Output/Model/BitfieldFactory.cs new file mode 100644 index 000000000..8d303e4b4 --- /dev/null +++ b/GirLoader/Output/Model/BitfieldFactory.cs @@ -0,0 +1,47 @@ +using System; +using System.Linq; + +namespace GirLoader.Output.Model +{ + internal class BitfieldFactory + { + private readonly MemberFactory _memberFactory; + + public BitfieldFactory(MemberFactory memberFactory) + { + _memberFactory = memberFactory; + } + + public Bitfield Create(Input.Model.Bitfield bitfield, Repository repository) + { + if (bitfield.Name is null) + throw new Exception("Bitfield has no name"); + + if (bitfield.Type is null) + throw new Exception("Bitfield is missing a type"); + + var members = bitfield.Members.Select(_memberFactory.Create).ToList(); + + bool ValueIsULong(Member member) + { + // Bitfields are transfered as ulong and thus do not support negative values. + // Negative values can occur as C convenience members as a "mask". + // Those can safely be should be ignored. + + if (ulong.TryParse(member.Value, out var _)) + return true; + + Log.Verbose($"{nameof(Bitfield)} - {member.OriginalName} ignored because value is no ulong: {member.Value}"); + return false; + } + + return new Bitfield( + repository: repository, + originalName: new TypeName(bitfield.Name), + name: new TypeName(bitfield.Name), + members: members.Where(ValueIsULong), + cType: new CType(bitfield.Type) + ); + } + } +} diff --git a/GirLoader/Output/Model/Enumeration.cs b/GirLoader/Output/Model/Enumeration.cs index e62057783..23d53be0e 100644 --- a/GirLoader/Output/Model/Enumeration.cs +++ b/GirLoader/Output/Model/Enumeration.cs @@ -6,12 +6,10 @@ namespace GirLoader.Output.Model { public class Enumeration : ComplexType { - public bool HasFlags { get; } public IEnumerable Members { get; } - public Enumeration(Repository repository, CType? cType, TypeName originalName, TypeName name, bool hasFlags, IEnumerable members) : base(repository, cType, name, originalName) + public Enumeration(Repository repository, CType? cType, TypeName originalName, TypeName name, IEnumerable members) : base(repository, cType, name, originalName) { - HasFlags = hasFlags; Members = members; } @@ -23,12 +21,17 @@ internal override bool GetIsResolved() internal override bool Matches(TypeReference typeReference) { + if (typeReference.SymbolNameReference is not null) + { + var namespaceOk = typeReference.SymbolNameReference.NamespaceName == Repository.Namespace.Name + || typeReference.SymbolNameReference.NamespaceName == null; + + return namespaceOk && typeReference.SymbolNameReference.SymbolName == OriginalName; + } + if (typeReference.CTypeReference is not null) return typeReference.CTypeReference.CType == CType; - if (typeReference.SymbolNameReference is not null) - return typeReference.SymbolNameReference.SymbolName == OriginalName; - return false; } } diff --git a/GirLoader/Output/Model/EnumerationFactory.cs b/GirLoader/Output/Model/EnumerationFactory.cs index 7c9f69dfd..f13286f64 100644 --- a/GirLoader/Output/Model/EnumerationFactory.cs +++ b/GirLoader/Output/Model/EnumerationFactory.cs @@ -12,7 +12,7 @@ public EnumerationFactory(MemberFactory memberFactory) _memberFactory = memberFactory; } - public Enumeration Create(Input.Model.Enum @enum, Repository repository, bool hasFlags) + public Enumeration Create(Input.Model.Enum @enum, Repository repository) { if (@enum.Name is null) throw new Exception("Enum has no name"); @@ -24,7 +24,6 @@ public Enumeration Create(Input.Model.Enum @enum, Repository repository, bool ha repository: repository, originalName: new TypeName(@enum.Name), name: new TypeName(@enum.Name), - hasFlags: hasFlags, members: @enum.Members.Select(_memberFactory.Create).ToList(), cType: new CType(@enum.Type) ); diff --git a/GirLoader/Output/Model/Namespace.cs b/GirLoader/Output/Model/Namespace.cs index ad6ccb03f..2ad4e9e24 100644 --- a/GirLoader/Output/Model/Namespace.cs +++ b/GirLoader/Output/Model/Namespace.cs @@ -28,8 +28,8 @@ public class Namespace private readonly List _enumerations = new(); public IEnumerable Enumerations => _enumerations; - private readonly List _bitfields = new(); - public IEnumerable Bitfields => _bitfields; + private readonly List _bitfields = new(); + public IEnumerable Bitfields => _bitfields; private readonly List _interfaces = new(); public IEnumerable Interfaces => _interfaces; @@ -69,7 +69,7 @@ internal void AddClass(Class @class) internal void AddEnumeration(Enumeration enumeration) => _enumerations.Add(enumeration); - internal void AddBitfield(Enumeration enumeration) + internal void AddBitfield(Bitfield enumeration) => _bitfields.Add(enumeration); internal void AddInterface(Interface @interface) diff --git a/GirLoader/Output/Model/NamespaceFactory.cs b/GirLoader/Output/Model/NamespaceFactory.cs index 653ddeda8..e6a188bf0 100644 --- a/GirLoader/Output/Model/NamespaceFactory.cs +++ b/GirLoader/Output/Model/NamespaceFactory.cs @@ -9,18 +9,20 @@ internal class NamespaceFactory private readonly AliasFactory _aliasFactory; private readonly CallbackFactory _callbackFactory; private readonly EnumerationFactory _enumerationFactory; + private readonly BitfieldFactory _bitfieldFactory; private readonly InterfaceFactory _interfaceFactory; private readonly RecordFactory _recordFactory; private readonly MethodFactory _methodFactory; private readonly ConstantFactory _constantFactory; private readonly UnionFactory _unionFactory; - public NamespaceFactory(ClassFactory classFactory, AliasFactory aliasFactory, CallbackFactory callbackFactory, EnumerationFactory enumerationFactory, InterfaceFactory interfaceFactory, RecordFactory recordFactory, MethodFactory methodFactory, ConstantFactory constantFactory, UnionFactory unionFactory) + public NamespaceFactory(ClassFactory classFactory, AliasFactory aliasFactory, CallbackFactory callbackFactory, EnumerationFactory enumerationFactory, BitfieldFactory bitfieldFactory,InterfaceFactory interfaceFactory, RecordFactory recordFactory, MethodFactory methodFactory, ConstantFactory constantFactory, UnionFactory unionFactory) { _classFactory = classFactory; _aliasFactory = aliasFactory; _callbackFactory = callbackFactory; _enumerationFactory = enumerationFactory; + _bitfieldFactory = bitfieldFactory; _interfaceFactory = interfaceFactory; _recordFactory = recordFactory; _methodFactory = methodFactory; @@ -85,13 +87,13 @@ private void SetCallbacks(Repository repository, IEnumerable enumerations) { foreach (Input.Model.Enum @enum in enumerations) - repository.Namespace.AddEnumeration(_enumerationFactory.Create(@enum, repository, false)); + repository.Namespace.AddEnumeration(_enumerationFactory.Create(@enum, repository)); } - private void SetBitfields(Repository repository, IEnumerable enumerations) + private void SetBitfields(Repository repository, IEnumerable bitfields) { - foreach (Input.Model.Enum @enum in enumerations) - repository.Namespace.AddBitfield(_enumerationFactory.Create(@enum, repository, true)); + foreach (Input.Model.Bitfield bitfield in bitfields) + repository.Namespace.AddBitfield(_bitfieldFactory.Create(bitfield, repository)); } private void SetInterfaces(Repository repository, IEnumerable interfaces) diff --git a/GirLoader/Output/Model/PrimitiveValueType.cs b/GirLoader/Output/Model/PrimitiveValueType.cs index d761b4b9d..b4d03c729 100644 --- a/GirLoader/Output/Model/PrimitiveValueType.cs +++ b/GirLoader/Output/Model/PrimitiveValueType.cs @@ -12,8 +12,8 @@ internal override bool Matches(TypeReference typeReference) { return typeReference switch { - { CTypeReference: { } cr } => cr.CType == CType, { SymbolNameReference: { SymbolName: { } sn } } => sn.Value == CType?.Value, + { CTypeReference: { } cr } => cr.CType == CType, _ => throw new Exception($"Can't match {GetType().Name} with {nameof(TypeReference)} {typeReference}") }; } diff --git a/GirLoader/Output/Model/Type.cs b/GirLoader/Output/Model/Type.cs index 1d0bbaf26..736f13e73 100644 --- a/GirLoader/Output/Model/Type.cs +++ b/GirLoader/Output/Model/Type.cs @@ -27,5 +27,8 @@ public string GetMetadataString(string key) internal abstract bool Matches(TypeReference typeReference); internal abstract IEnumerable GetTypeReferences(); internal abstract bool GetIsResolved(); + + public override string ToString() + => Name; } } diff --git a/GirLoader/Output/Module.cs b/GirLoader/Output/Module.cs index 59f2014db..e981f8a2f 100644 --- a/GirLoader/Output/Module.cs +++ b/GirLoader/Output/Module.cs @@ -16,6 +16,7 @@ namespace GirLoader.Output [Register(typeof(Model.ParameterListFactory))] [Register(typeof(Model.CallbackFactory))] [Register(typeof(Model.EnumerationFactory))] + [Register(typeof(Model.BitfieldFactory))] [Register(typeof(Model.InterfaceFactory))] [Register(typeof(Model.RecordFactory))] [Register(typeof(Model.MethodFactory))] diff --git a/Libs/GObject-2.0/Records/Value.cs b/Libs/GObject-2.0/Records/Value.cs index 97efb2959..7e4360555 100644 --- a/Libs/GObject-2.0/Records/Value.cs +++ b/Libs/GObject-2.0/Records/Value.cs @@ -171,7 +171,7 @@ public void Set(object? value) public long GetLong() => Native.Value.Methods.GetLong(Handle); public double GetDouble() => Native.Value.Methods.GetDouble(Handle); public float GetFloat() => Native.Value.Methods.GetFloat(Handle); - public long GetFlags() => Native.Value.Methods.GetFlags(Handle); + public ulong GetFlags() => Native.Value.Methods.GetFlags(Handle); public long GetEnum() => Native.Value.Methods.GetEnum(Handle); public string? GetString() => StringHelper.ToNullableStringUtf8(Native.Value.Methods.GetString(Handle));