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;
+}
+```
+
+