diff --git a/README.md b/README.md index c3223e5..47a4f28 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,8 @@ Based on C# 15's Union type support, EfficientUnionGenerator provides highly eff EfficientUnionGenerator regards structs which are annotated with `EfficientUnion.EfficientUnionAttribute` as union types and generates union type support for them. Also it regards public partial constructors with single parameter as the members of the union. +#### Simple union + Following code is the most simple example of how to use EfficientUnionGenerator. ```csharp @@ -31,6 +33,94 @@ public readonly partial struct Int32OrString } ``` +
+ +generation result + +```csharp +// +#nullable enable +namespace EfficientUnionGenerator.SampleApp.SimpleUnionOfInt32OrString; + + +partial struct Int32OrString +{ + private enum __TypeSpecifier : byte + { + __int = 1, + + __Undefined = 0, + } + + private const bool __defaultTypeSpecifierHasType = false; + [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)] + private struct __UnmanagedField + { + [System.Runtime.InteropServices.FieldOffset(0)] public int __int; + } + + private readonly __UnmanagedField __unmanagedField; + private readonly __TypeSpecifier __typeSpecifier; + + private bool HasUnmanagedValue => __typeSpecifier != __TypeSpecifier.__Undefined || __defaultTypeSpecifierHasType; + private object? UnmanagedValue => __typeSpecifier switch + { + __TypeSpecifier.__int => __unmanagedField.__int, + _ => null, + }; + + public partial Int32OrString(int x) + { + __unmanagedField = new() + { + __int = x, + }; + __typeSpecifier = __TypeSpecifier.__int; + } + public bool TryGetValue(out int value) + { + if (__typeSpecifier == __TypeSpecifier.__int) + { + value = __unmanagedField.__int; + return true; + } + else + { + value = default; + return false; + } + } + + private readonly object? __managedField; + + public partial Int32OrString(string x) + { + __managedField = x; + } + + public bool TryGetValue([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out string? value) + { + if (__managedField is string __casted) + { + value = __casted; + return true; + } + else + { + value = default; + return false; + } + } + + public bool HasValue => HasUnmanagedValue || __managedField is not null; + public object? Value => HasUnmanagedValue ? UnmanagedValue : __managedField; +} +``` + +
+ +#### Make as an unmanaged + If all of the members of the union are unmanaged types, the union type gets also unmanaged type. ```csharp @@ -47,6 +137,148 @@ public readonly partial struct SignedInteger } ``` +
+ +generation result + +```csharp +// +#nullable enable +namespace EfficientUnionGenerator.SampleApp.SimpleUnionOfSignedInteger; + + +partial struct SignedInteger +{ + private enum __TypeSpecifier : byte + { + __sbyte = 1, + __short = 2, + __int = 3, + __long = 4, + + __Undefined = 0, + } + + private const bool __defaultTypeSpecifierHasType = false; + [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)] + private struct __UnmanagedField + { + [System.Runtime.InteropServices.FieldOffset(0)] public sbyte __sbyte; + [System.Runtime.InteropServices.FieldOffset(0)] public short __short; + [System.Runtime.InteropServices.FieldOffset(0)] public int __int; + [System.Runtime.InteropServices.FieldOffset(0)] public long __long; + } + + private readonly __UnmanagedField __unmanagedField; + private readonly __TypeSpecifier __typeSpecifier; + + private bool HasUnmanagedValue => __typeSpecifier != __TypeSpecifier.__Undefined || __defaultTypeSpecifierHasType; + private object? UnmanagedValue => __typeSpecifier switch + { + __TypeSpecifier.__sbyte => __unmanagedField.__sbyte, + __TypeSpecifier.__short => __unmanagedField.__short, + __TypeSpecifier.__int => __unmanagedField.__int, + __TypeSpecifier.__long => __unmanagedField.__long, + _ => null, + }; + + public partial SignedInteger(sbyte x) + { + __unmanagedField = new() + { + __sbyte = x, + }; + __typeSpecifier = __TypeSpecifier.__sbyte; + } + public bool TryGetValue(out sbyte value) + { + if (__typeSpecifier == __TypeSpecifier.__sbyte) + { + value = __unmanagedField.__sbyte; + return true; + } + else + { + value = default; + return false; + } + } + + public partial SignedInteger(short x) + { + __unmanagedField = new() + { + __short = x, + }; + __typeSpecifier = __TypeSpecifier.__short; + } + public bool TryGetValue(out short value) + { + if (__typeSpecifier == __TypeSpecifier.__short) + { + value = __unmanagedField.__short; + return true; + } + else + { + value = default; + return false; + } + } + + public partial SignedInteger(int x) + { + __unmanagedField = new() + { + __int = x, + }; + __typeSpecifier = __TypeSpecifier.__int; + } + public bool TryGetValue(out int value) + { + if (__typeSpecifier == __TypeSpecifier.__int) + { + value = __unmanagedField.__int; + return true; + } + else + { + value = default; + return false; + } + } + + public partial SignedInteger(long x) + { + __unmanagedField = new() + { + __long = x, + }; + __typeSpecifier = __TypeSpecifier.__long; + } + public bool TryGetValue(out long value) + { + if (__typeSpecifier == __TypeSpecifier.__long) + { + value = __unmanagedField.__long; + return true; + } + else + { + value = default; + return false; + } + } + + public bool HasValue => HasUnmanagedValue; + public object? Value => UnmanagedValue; +} +``` + +
+ +#### Field mask + You can specify the bit mask for type identifier by `unmanagedFieldMask` property of `EfficientUnionAttribute`. ```csharp @@ -71,6 +303,117 @@ public static class Program } ``` +
+ +generation result + +```csharp +// +#nullable enable +namespace EfficientUnionGenerator.SampleApp.PositiveOnlyIntOrFloat; + + +partial struct PositiveOnlyIntOrFloat +{ + private enum __TypeSpecifier : uint + { + __int = 0, + __float = 2147483648, + + __Undefined = 0, + } + + private const bool __defaultTypeSpecifierHasType = true; + private const __TypeSpecifier __typeSpecifierBitMask = unchecked((__TypeSpecifier)2147483648); + + [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)] + private struct __UnmanagedField + { + [System.Runtime.InteropServices.FieldOffset(0)] public __TypeSpecifier __typeSpecifier; + [System.Runtime.InteropServices.FieldOffset(0)] public int __int; + [System.Runtime.InteropServices.FieldOffset(0)] public float __float; + } + + private readonly __UnmanagedField __unmanagedField; + private readonly __TypeSpecifier __typeSpecifier + { + get => __unmanagedField.__typeSpecifier & __typeSpecifierBitMask; + init => __unmanagedField.__typeSpecifier |= value; + } + + private bool HasUnmanagedValue => __typeSpecifier != __TypeSpecifier.__Undefined || __defaultTypeSpecifierHasType; + private object? UnmanagedValue + { + get + { + var maskedField = __unmanagedField; + maskedField.__typeSpecifier &= ~__typeSpecifierBitMask; + return __typeSpecifier switch + { + __TypeSpecifier.__int => maskedField.__int, + __TypeSpecifier.__float => maskedField.__float, + _ => null, + }; + } + } + + public partial PositiveOnlyIntOrFloat(int value) + { + __unmanagedField = new() + { + __int = value, + }; + __typeSpecifier = __TypeSpecifier.__int; + } + public bool TryGetValue(out int value) + { + if (__typeSpecifier == __TypeSpecifier.__int) + { + var maskedField = __unmanagedField; + maskedField.__typeSpecifier &= ~__typeSpecifierBitMask; + value = maskedField.__int; + return true; + } + else + { + value = default; + return false; + } + } + + public partial PositiveOnlyIntOrFloat(float value) + { + __unmanagedField = new() + { + __float = value, + }; + __typeSpecifier = __TypeSpecifier.__float; + } + public bool TryGetValue(out float value) + { + if (__typeSpecifier == __TypeSpecifier.__float) + { + var maskedField = __unmanagedField; + maskedField.__typeSpecifier &= ~__typeSpecifierBitMask; + value = maskedField.__float; + return true; + } + else + { + value = default; + return false; + } + } + + public bool HasValue => HasUnmanagedValue; + public object? Value => UnmanagedValue; +} +``` + +
+ +#### Explicit type identifier value + You can specify the type identifier value by using `EfficientUnion.EnumBitPatternAttribute`. This is useful for such case of struct unions identified by version number field. @@ -91,3 +434,105 @@ public readonly partial struct ElfHeader [EnumBitPattern(0x00_00_00_02_00_00_00_00uL)] public partial ElfHeader(Elf64Header x); } ``` + +
+ +generation result + +```csharp +// +#nullable enable +namespace EfficientUnionGenerator.SampleApp.ElfHeader; + + +partial struct ElfHeader +{ + private enum __TypeSpecifier : ulong + { + __EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf32Header = 4294967296, + __EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf64Header = 8589934592, + + __Undefined = 0, + } + + private const bool __defaultTypeSpecifierHasType = false; + private const __TypeSpecifier __typeSpecifierBitMask = unchecked((__TypeSpecifier)1095216660480); + + [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)] + private struct __UnmanagedField + { + [System.Runtime.InteropServices.FieldOffset(0)] public __TypeSpecifier __typeSpecifier; + [System.Runtime.InteropServices.FieldOffset(0)] public EfficientUnionGenerator.SampleApp.ElfHeader.Elf32Header __EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf32Header; + [System.Runtime.InteropServices.FieldOffset(0)] public EfficientUnionGenerator.SampleApp.ElfHeader.Elf64Header __EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf64Header; + } + + private readonly __UnmanagedField __unmanagedField; + private readonly __TypeSpecifier __typeSpecifier + { + get => __unmanagedField.__typeSpecifier & __typeSpecifierBitMask; + init => __unmanagedField.__typeSpecifier |= value; + } + + private bool HasUnmanagedValue => __typeSpecifier != __TypeSpecifier.__Undefined || __defaultTypeSpecifierHasType; + private object? UnmanagedValue + { + get + { + var maskedField = __unmanagedField; + return __typeSpecifier switch + { + __TypeSpecifier.__EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf32Header => maskedField.__EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf32Header, + __TypeSpecifier.__EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf64Header => maskedField.__EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf64Header, + _ => null, + }; + } + } + + public partial ElfHeader(EfficientUnionGenerator.SampleApp.ElfHeader.Elf32Header x) + { + __unmanagedField = new() + { + __EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf32Header = x, + }; + } + public bool TryGetValue(out EfficientUnionGenerator.SampleApp.ElfHeader.Elf32Header value) + { + if (__typeSpecifier == __TypeSpecifier.__EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf32Header) + { + value = __unmanagedField.__EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf32Header; + return true; + } + else + { + value = default; + return false; + } + } + + public partial ElfHeader(EfficientUnionGenerator.SampleApp.ElfHeader.Elf64Header x) + { + __unmanagedField = new() + { + __EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf64Header = x, + }; + } + public bool TryGetValue(out EfficientUnionGenerator.SampleApp.ElfHeader.Elf64Header value) + { + if (__typeSpecifier == __TypeSpecifier.__EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf64Header) + { + value = __unmanagedField.__EfficientUnionGenerator_u002E_SampleApp_u002E_ElfHeader_u002E_Elf64Header; + return true; + } + else + { + value = default; + return false; + } + } + + public bool HasValue => HasUnmanagedValue; + public object? Value => UnmanagedValue; +} +``` + +