public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
        {
            if (!(context.Node is StructDeclarationSyntax dec) ||
                dec.AttributeLists.Count <= 0)
            {
                return;
            }

            if (UnionDefinition.TryCreate(context, dec, out var def))
            {
                this.Definitions.Add(def);
            }
        }
        private static void AppendMethod_Set(UnionDefinition def, StringBuilder builder)
        {
            var pre_ = def.GetMemberPrefix();

            foreach (var member in def.Members)
            {
                builder.Append($@"
        public void Set({member.Type} value)
        {{
            this.{pre_}ValueType = Type.{member.Name};
            this.{pre_}{member.Name} = value;
        }}
");
            }
        }
        private static void AppendEnum_Type(UnionDefinition def, StringBuilder builder)
        {
            string underlyingType;
            var    memberCount = (ulong)def.Members.Count;

            if (memberCount <= 255)
            {
                underlyingType = "byte";
            }
            else if (memberCount <= 32767)
            {
                underlyingType = "short";
            }
            else if (memberCount <= 65535)
            {
                underlyingType = "ushort";
            }
            else if (memberCount <= 2147483647)
            {
                underlyingType = "int";
            }
            else if (memberCount <= 42949672955)
            {
                underlyingType = "uint";
            }
            else if (memberCount <= 9223372036854775807)
            {
                underlyingType = "long";
            }
            else
            {
                underlyingType = "ulong";
            }

            builder.Append($@"
        public enum Type : {underlyingType}
        {{");

            foreach (var member in def.Members)
            {
                builder.Append($@"
            {member.Name},");
            }

            builder.Append(@"
        }
");
        }
        private static void AppendMethod_GetUnderlyingType(UnionDefinition def, StringBuilder builder)
        {
            var pre_ = def.GetMemberPrefix();

            builder.Append($@"
        public System.Type GetUnderlyingType()");

            if (def.Members.Count < 3)
            {
                builder.Append(@"
        {");

                foreach (var member in def.Members)
                {
                    builder.Append($@"
            if (this.{pre_}ValueType == Type.{member.Name})
                return this.{pre_}{member.Name}.GetType();
");
                }

                builder.Append(@"
            return this.GetType();
        }
");
            }
            else
            {
                builder.Append($@"
        {{
            switch (this.{pre_}ValueType)
            {{");

                foreach (var member in def.Members)
                {
                    builder.Append($@"
                case Type.{member.Name}: return this.{pre_}{member.Name}.GetType();");
                }

                builder.Append(@"
            }

            return this.GetType();
        }
");
            }
        }
        private static void AppendUsings(UnionDefinition def, StringBuilder unionBuilder, StringBuilder usingBuilder)
        {
            foreach (var ns in def.GlobalNamespaces)
            {
                usingBuilder.AppendLine($"using {ns};");
            }

            if (def.LocalNamespaces.Count > 0)
            {
                unionBuilder.AppendLine();

                foreach (var ns in def.LocalNamespaces)
                {
                    unionBuilder.AppendLine($"    using {ns};");
                }
            }
        }
        private static void AppendMethod_GetHashCode(UnionDefinition def, StringBuilder builder)
        {
            var pre_ = def.GetMemberPrefix();

            builder.Append($@"
        public override int GetHashCode()
        {{
            var hash = EqualityComparer<Type>.Default.GetHashCode(this.{pre_}ValueType) * -1521134295;
");

            if (def.Members.Count < 3)
            {
                foreach (var member in def.Members)
                {
                    builder.Append($@"
            if (this.{pre_}ValueType == Type.{member.Name})
                return hash + EqualityComparer<{member.Type}>.Default.GetHashCode(this.{pre_}{member.Name});
");
                }

                builder.Append(@"
            return hash;
        }
");
            }
            else
            {
                builder.Append($@"
            switch (this.{pre_}ValueType)
            {{");

                foreach (var member in def.Members)
                {
                    builder.Append($@"
                case Type.{member.Name}: return hash + EqualityComparer<{member.Type}>.Default.GetHashCode(this.{pre_}{member.Name});");
                }

                builder.Append(@"
            }

            return hash;
        }
");
            }
        }
        private static void AppendConstructors(UnionDefinition def, StringBuilder builder)
        {
            var pre_ = def.GetMemberPrefix();
            var last = def.Members.Count - 1;

            for (var i = 0; i < def.Members.Count; i++)
            {
                var member = def.Members[i];

                if (i > 0)
                {
                    builder.AppendLine();
                }

                builder.Append($@"
        public {def.Name}({member.Type} value)
        {{
            this.{pre_}ValueType = Type.{member.Name};
");

                for (var k = 0; k < def.Members.Count; k++)
                {
                    if (k == i)
                    {
                        continue;
                    }

                    var memberOther = def.Members[k];

                    builder.Append($@"
            this.{pre_}{memberOther.Name} = default;");
                }

                builder.Append($@"

            this.{pre_}{member.Name} = value;
        }}");

                if (i == last)
                {
                    builder.AppendLine();
                }
            }
        }
        public void Execute(GeneratorExecutionContext context, UnionDefinition def)
        {
            var usingBuilder = new StringBuilder($@"using {GeneratorConfig.Namespace};
");

            var unionBuilder = new StringBuilder($@"
namespace {def.Namespace}
{{
    using System.Runtime.InteropServices;
");

            AppendUsings(def, unionBuilder, usingBuilder);

            unionBuilder.Append($@"
    [StructLayout(LayoutKind.Explicit, Pack = 1)]
    public partial struct {def.Name}
    {{");

            AppendEnum_Type(def, unionBuilder);
            AppendProp_ValueType(def, unionBuilder);
            AppendProps(def, unionBuilder);
            AppendConstructors(def, unionBuilder);
            AppendConstructorTypeParam(def, unionBuilder);

            if (!def.IsReadOnly)
            {
                AppendMethod_Set(def, unionBuilder);
            }

            AppendMethod_TryGet(def, unionBuilder);
            AppendMethod_GetUnderlyingType(def, unionBuilder);
            AppendMethod_GetHashCode(def, unionBuilder);
            AppendMethod_Equals(def, unionBuilder);
            AppendMethod_ToString(def, unionBuilder);
            AppendOperator_Implicit(def, unionBuilder);

            unionBuilder.Append(@"
    }
}");
            usingBuilder.AppendLine(unionBuilder.ToString());
            context.AddSource($"Union_{def.Name}.cs", SourceText.From(usingBuilder.ToString(), Encoding.UTF8));
        }
        private static void AppendConstructorTypeParam(UnionDefinition def, StringBuilder builder)
        {
            var pre_ = def.GetMemberPrefix();

            builder.Append($@"
        public {def.Name}(Type type)
        {{
            this.{pre_}ValueType = type;
");

            foreach (var member in def.Members)
            {
                builder.Append($@"
            this.{pre_}{member.Name} = default;");
            }

            builder.Append(@"
        }
");
        }
        private static void AppendMethod_ToString(UnionDefinition def, StringBuilder builder)
        {
            var pre_ = def.GetMemberPrefix();

            builder.Append(@"
        public override string ToString()
        {");

            if (def.Members.Count < 3)
            {
                foreach (var member in def.Members)
                {
                    builder.Append($@"
            if (this.{pre_}ValueType == Type.{member.Name})
                return this.{pre_}{member.Name}.ToString();
");
                }

                builder.Append(@"
            return string.Empty;
        }");
            }
            else
            {
                builder.Append($@"
            switch (this.{pre_}ValueType)
            {{");

                foreach (var member in def.Members)
                {
                    builder.Append($@"
                case Type.{member.Name}: return this.{pre_}{member.Name}.ToString();");
                }

                builder.Append(@"
            }

            return string.Empty;
        }");
            }
        }
        private static void AppendMethod_TryGet(UnionDefinition def, StringBuilder builder)
        {
            var pre_ = def.GetMemberPrefix();

            foreach (var member in def.Members)
            {
                builder.Append($@"
        public bool TryGet(out {member.Type} value)
        {{
            if (this.{pre_}ValueType != Type.{member.Name})
            {{
                value = default;
                return false;
            }}

            value = this.{pre_}{member.Name};
            return true;
        }}
");
            }
        }
        private static void AppendProp_ValueType(UnionDefinition def, StringBuilder builder)
        {
            if (def.IsReadOnly && def.InvalidValueAccess == InvalidValueAccess.Allow)
            {
                builder.Append(@"
        [FieldOffset(0)]
        public readonly Type ValueType;
");
            }
            else
            {
                var readonlyKeyword = def.IsReadOnly ? "readonly " : string.Empty;

                builder.Append($@"
        [FieldOffset(0)]
        private {readonlyKeyword}Type m_ValueType;

        public Type ValueType => this.m_ValueType;
");
            }
        }
        private static void AppendOperator_Implicit(UnionDefinition def, StringBuilder builder)
        {
            var pre_ = def.GetMemberPrefix();
            var last = def.Members.Count - 1;

            switch (def.InvalidValueAccess)
            {
            case InvalidValueAccess.ThrowException:
            {
                for (var i = 0; i < def.Members.Count; i++)
                {
                    var member = def.Members[i];

                    if (i <= 0)
                    {
                        builder.AppendLine();
                    }

                    builder.Append($@"
        public static implicit operator {def.Name}({member.Type} value)
            => new {def.Name}(value);
");

                    builder.Append($@"
        public static implicit operator {member.Type}(in {def.Name} value)
        {{
            if (value.{pre_}ValueType == Type.{member.Name})
                return value.{pre_}{member.Name};

            throw new InvalidValueAccessException($""Cannot implicitly convert underlying type '{{value.GetUnderlyingType().GetNiceFullName()}}' to '{member.Type}'"");
        }}");

                    if (i < last)
                    {
                        builder.AppendLine();
                    }
                }
                break;
            }

            case InvalidValueAccess.ReturnDefault:
            {
                for (var i = 0; i < def.Members.Count; i++)
                {
                    var member = def.Members[i];

                    if (i <= 0)
                    {
                        builder.AppendLine();
                    }

                    builder.Append($@"
        public static implicit operator {def.Name}({member.Type} value)
            => new {def.Name}(value);
");

                    builder.Append($@"
        public static implicit operator {member.Type}(in {def.Name} value)
        {{
            if (value.{pre_}ValueType == Type.{member.Name})
                return value.{pre_}{member.Name};

            return default;
        }}");

                    if (i < last)
                    {
                        builder.AppendLine();
                    }
                }
                break;
            }

            default:
            {
                for (var i = 0; i < def.Members.Count; i++)
                {
                    var member = def.Members[i];

                    if (i <= 0)
                    {
                        builder.AppendLine();
                    }

                    builder.Append($@"
        public static implicit operator {def.Name}({member.Type} value)
            => new {def.Name}(value);
");

                    builder.Append($@"
        public static implicit operator {member.Type}(in {def.Name} value)
            => value.{pre_}{member.Name};");

                    if (i < last)
                    {
                        builder.AppendLine();
                    }
                }
                break;
            }
            }
        }
        public static bool TryCreate(GeneratorSyntaxContext context, StructDeclarationSyntax dec, out UnionOperatorDefinition def)
        {
            if (!UnionDefinition.TryCreate(context, dec, out var unionDef))
            {
                def = default;
                return(false);
            }

            var attributes = new List <AttributeSyntax>();

            foreach (var attribList in dec.AttributeLists)
            {
                foreach (var attrib in attribList.Attributes)
                {
                    var name = attrib.Name.ToString();

                    if (string.Equals(name, "UnionOperator") ||
                        string.Equals(name, "UnionOperatorAttribute"))
                    {
                        attributes.Add(attrib);
                        break;
                    }
                }
            }

            if (attributes.Count < 1)
            {
                def = default;
                return(false);
            }

            var operators    = new List <Operator>();
            var operatorSet  = new HashSet <Op>();
            var operatorList = new List <Op>();

            foreach (var attribute in attributes)
            {
                var operandTypeHandling = OperandTypeHandling.Implicit;

                foreach (var arg in attribute.ArgumentList.Arguments)
                {
                    if (!(arg.Expression is MemberAccessExpressionSyntax memberAccess))
                    {
                        continue;
                    }

                    var memberName = memberAccess.Expression.ToString();

                    if (string.Equals(memberName, nameof(Op)))
                    {
                        if (Enum.TryParse <Op>(memberAccess.Name.ToString(), true, out var value) &&
                            !operatorSet.Contains(value))
                        {
                            operatorSet.Add(value);
                            operatorList.Add(value);
                        }
                    }
                    else if (string.Equals(memberName, nameof(OperandTypeHandling)))
                    {
                        if (Enum.TryParse <OperandTypeHandling>(memberAccess.Name.ToString(), true, out var value))
                        {
                            operandTypeHandling = value;
                        }
                    }
                }

                foreach (var op in operatorList)
                {
                    operators.Add(new Operator(op, operandTypeHandling));
                }

                operatorList.Clear();
            }

            if (operators.Count < 1)
            {
                def = default;
                return(false);
            }

            def = new UnionOperatorDefinition {
                UnionDefinition = unionDef
            };

            for (var i = 0; i < operators.Count; i++)
            {
                def.Operators.Add(operators[i]);
            }

            return(true);
        }
        private static void AppendProps(UnionDefinition def, StringBuilder builder)
        {
            if (def.IsReadOnly && def.InvalidValueAccess == InvalidValueAccess.Allow)
            {
                foreach (var member in def.Members)
                {
                    builder.Append($@"
        [FieldOffset(1)]
        public readonly {member.Type} {member.Name};
");
                }

                return;
            }

            var readonlyKeyword = def.IsReadOnly ? "readonly " : string.Empty;

            foreach (var member in def.Members)
            {
                builder.Append($@"
        [FieldOffset(1)]
        private {readonlyKeyword}{member.Type} m_{member.Name};
");
            }

            switch (def.InvalidValueAccess)
            {
            case InvalidValueAccess.ThrowException:
            {
                foreach (var member in def.Members)
                {
                    builder.Append($@"
        public {member.Type} {member.Name}
        {{
            get
            {{
                if (this.m_ValueType == Type.{member.Name})
                    return this.m_{member.Name};

                throw new InvalidValueAccessException($""Cannot convert underlying type '{{GetUnderlyingType().GetNiceFullName()}}' to '{member.Type}'"");
            }}
        }}
");
                }
                break;
            }

            case InvalidValueAccess.ReturnDefault:
            {
                foreach (var member in def.Members)
                {
                    builder.Append($@"
        public {member.Type} {member.Name}
        {{
            get
            {{
                if (this.m_ValueType == Type.{member.Name})
                    return this.m_{member.Name};

                return default;
            }}
        }}
");
                }
                break;
            }

            default:
            {
                foreach (var member in def.Members)
                {
                    builder.Append($@"
        public {member.Type} {member.Name} => this.m_{member.Name};
");
                }
                break;
            }
            }
        }
        public static bool TryCreate(GeneratorSyntaxContext context, StructDeclarationSyntax dec, out UnionDefinition def)
        {
            AttributeSyntax attribute = null;

            foreach (var attribList in dec.AttributeLists)
            {
                foreach (var attrib in attribList.Attributes)
                {
                    var name = attrib.Name.ToString();

                    if (string.Equals(name, "Union") ||
                        string.Equals(name, "UnionAttribute"))
                    {
                        attribute = attrib;
                        break;
                    }
                }
            }

            if (attribute == null ||
                attribute.ArgumentList == null ||
                attribute.ArgumentList.Arguments.Count < 1)
            {
                def = default;
                return(false);
            }

            TypeOfExpressionSyntax       typeOf       = null;
            MemberAccessExpressionSyntax memberAccess = null;

            foreach (var arg in attribute.ArgumentList.Arguments)
            {
                if (arg.Expression is TypeOfExpressionSyntax typeOfSyntax)
                {
                    typeOf = typeOfSyntax;
                }
                else if (arg.Expression is MemberAccessExpressionSyntax memberAccessSyntax)
                {
                    memberAccess = memberAccessSyntax;
                }
            }

            if (typeOf == null || !(typeOf.Type is TupleTypeSyntax tuple) ||
                tuple.Elements.Count <= 0)
            {
                def = default;
                return(false);
            }

            def = new UnionDefinition {
                Name = dec.Identifier.ToString(),
                InvalidValueAccess = InvalidValueAccess.Allow
            };

            def.GetGlobalNamespaces(dec);
            def.GetLocalNamespaces(dec);

            foreach (var element in tuple.Elements)
            {
                GetName(context.SemanticModel, element, out var type, out var name);
                def.Members.Add(new MemberDefinition(type, name));
            }

            foreach (var keyword in dec.Modifiers)
            {
                if (string.Equals(keyword.ToString(), "readonly"))
                {
                    def.IsReadOnly = true;
                }
            }

            if (memberAccess != null &&
                string.Equals(memberAccess.Expression.ToString(), nameof(InvalidValueAccess)))
            {
                if (Enum.TryParse <InvalidValueAccess>(memberAccess.Name.ToString(), true, out var value))
                {
                    def.InvalidValueAccess = value;
                }
            }

            return(true);
        }
        private static void AppendMethod_Equals(UnionDefinition def, StringBuilder builder)
        {
            var pre_ = def.GetMemberPrefix();

            builder.Append($@"
        public override bool Equals(object obj)
            => obj is {def.Name} other && Equals(in this, in other);

        public bool Equals({def.Name} other)
            => Equals(in this, in other);

        public bool Equals(in {def.Name} other)
            => Equals(in this, in other);
");

            builder.Append($@"
        public static bool Equals(in {def.Name} a, in {def.Name} b)");

            if (def.Members.Count < 3)
            {
                builder.Append($@"
        {{
            if (a.{pre_}ValueType != b.{pre_}ValueType)
                return false;
");

                foreach (var member in def.Members)
                {
                    builder.Append($@"
            if (a.{pre_}ValueType == Type.{member.Name})
                return EqualityComparer<{member.Type}>.Default.Equals(a.{pre_}{member.Name}, b.{pre_}{member.Name});
");
                }

                builder.Append(@"
            return false;
        }
");
            }
            else
            {
                builder.Append($@"
        {{
            if (a.{pre_}ValueType != b.{pre_}ValueType)
                return false;

            switch (a.{pre_}ValueType)
            {{");

                foreach (var member in def.Members)
                {
                    builder.Append($@"
                case Type.{member.Name}: return EqualityComparer<{member.Type}>.Default.Equals(a.{pre_}{member.Name}, b.{pre_}{member.Name});");
                }

                builder.Append(@"
            }

            return false;
        }
");
            }

            builder.Append($@"
        public static bool operator ==(in {def.Name} left, in {def.Name} right)
            => Equals(in left, in right);

        public static bool operator !=(in {def.Name} left, in {def.Name} right)
            => !Equals(in left, in right);
");
        }