RSCG – UnionsGenerator

RSCG – UnionsGenerator
 
 

name UnionsGenerator
nuget https://www.nuget.org/packages/RhoMicro.CodeAnalysis.UnionsGenerator
link https://github.com/PaulBraetz/RhoMicro.CodeAnalysis/
author Paul Braetz

Generating Union types for C#

 

This is how you can use UnionsGenerator .

The code that you start with is


<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>

	<ItemGroup>
	  <PackageReference Include="RhoMicro.CodeAnalysis.UnionsGenerator" Version="14.0.2">
	    <PrivateAssets>all</PrivateAssets>
	    <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
	  </PackageReference>
	</ItemGroup>
</Project>


The code that you will use is


using UnionTypesDemo;

Console.WriteLine("Save or not");
var data = SaveToDatabase.Save(0);
Console.WriteLine(data.IsValidationError);
data = SaveToDatabase.Save(1);
Console.WriteLine(data.IsSuccess);



using RhoMicro.CodeAnalysis;
namespace UnionTypesDemo;
public record Success(int Value);
public record ValidationError(string Message);

[UnionType<Success>]
[UnionTypeAttribute<ValidationError>]
public partial class ResultSave
{
}





namespace UnionTypesDemo;

public class SaveToDatabase
{
    public static ResultSave Save(int i)
    {
        if(i ==0)
        {
            return new ValidationError(" cannot save 0");
        }
        return new Success(i);
    }
}




 

The code that is generated is

// <auto-generated>
// This file was generated by RhoMicro.CodeAnalysis.UnionsGenerator
// The tool used to generate this code may be subject to license terms;
// this generated code is however not subject to those terms, instead it is
// subject to the license (if any) applied to the containing project.
// </auto-generated>
#nullable enable
#pragma warning disable

namespace RhoMicro.CodeAnalysis
{
    using System;

    /// <summary>
    /// Marks the target type to be related to another union type.
    /// </summary>
    /// <typeparam name="T0">The type to register as related to the target union type.</typeparam>
    [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
#if UNIONS_GENERATOR
    [GenerateFactory(OmitTypeCheck = true)]
#endif
    sealed partial class RelationAttribute<T0> : Attribute
    { }
    /// <summary>
    /// Marks the target type to be related to other union types.
    /// </summary>
    /// <typeparam name="T0">The first type to register as related to the target union type.</typeparam>
    /// <typeparam name="T1">The second type to register as related to the target union type.</typeparam>
    [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
    sealed partial class RelationAttribute<T0, T1> : Attribute
    { }
    /// <summary>
    /// Marks the target type to be related to other union types.
    /// </summary>
    /// <typeparam name="T0">The first type to register as related to the target union type.</typeparam>
    /// <typeparam name="T1">The second type to register as related to the target union type.</typeparam>
    /// <typeparam name="T2">The third type to register as related to the target union type.</typeparam>
    [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
    sealed partial class RelationAttribute<T0, T1, T2> : Attribute
    { }
    /// <summary>
    /// Marks the target type to be related to other union types.
    /// </summary>
    /// <typeparam name="T0">The first type to register as related to the target union type.</typeparam>
    /// <typeparam name="T1">The second type to register as related to the target union type.</typeparam>
    /// <typeparam name="T2">The third type to register as related to the target union type.</typeparam>
    /// <typeparam name="T3">The fourth type to register as related to the target union type.</typeparam>
    [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
    sealed partial class RelationAttribute<T0, T1, T2, T3> : Attribute
    { }
    /// <summary>
    /// Marks the target type to be related to other union types.
    /// </summary>
    /// <typeparam name="T0">The first type to register as related to the target union type.</typeparam>
    /// <typeparam name="T1">The second type to register as related to the target union type.</typeparam>
    /// <typeparam name="T2">The third type to register as related to the target union type.</typeparam>
    /// <typeparam name="T3">The fourth type to register as related to the target union type.</typeparam>
    /// <typeparam name="T4">The fifth type to register as related to the target union type.</typeparam>
    [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
    sealed partial class RelationAttribute<T0, T1, T2, T3, T4> : Attribute
    { }
    /// <summary>
    /// Marks the target type to be related to other union types.
    /// </summary>
    /// <typeparam name="T0">The first type to register as related to the target union type.</typeparam>
    /// <typeparam name="T1">The second type to register as related to the target union type.</typeparam>
    /// <typeparam name="T2">The third type to register as related to the target union type.</typeparam>
    /// <typeparam name="T3">The fourth type to register as related to the target union type.</typeparam>
    /// <typeparam name="T4">The fifth type to register as related to the target union type.</typeparam>
    /// <typeparam name="T5">The sixth type to register as related to the target union type.</typeparam>
    [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
    sealed partial class RelationAttribute<T0, T1, T2, T3, T4, T5> : Attribute
    { }
    /// <summary>
    /// Marks the target type to be related to other union types.
    /// </summary>
    /// <typeparam name="T0">The first type to register as related to the target union type.</typeparam>
    /// <typeparam name="T1">The second type to register as related to the target union type.</typeparam>
    /// <typeparam name="T2">The third type to register as related to the target union type.</typeparam>
    /// <typeparam name="T3">The fourth type to register as related to the target union type.</typeparam>
    /// <typeparam name="T4">The fifth type to register as related to the target union type.</typeparam>
    /// <typeparam name="T5">The sixth type to register as related to the target union type.</typeparam>
    /// <typeparam name="T6">The seventh type to register as related to the target union type.</typeparam>
    [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
    sealed partial class RelationAttribute<T0, T1, T2, T3, T4, T5, T6> : Attribute
    { }
    /// <summary>
    /// Marks the target type to be related to other union types.
    /// </summary>
    /// <typeparam name="T0">The first type to register as related to the target union type.</typeparam>
    /// <typeparam name="T1">The second type to register as related to the target union type.</typeparam>
    /// <typeparam name="T2">The third type to register as related to the target union type.</typeparam>
    /// <typeparam name="T3">The fourth type to register as related to the target union type.</typeparam>
    /// <typeparam name="T4">The fifth type to register as related to the target union type.</typeparam>
    /// <typeparam name="T5">The sixth type to register as related to the target union type.</typeparam>
    /// <typeparam name="T6">The seventh type to register as related to the target union type.</typeparam>
    /// <typeparam name="T7">The eighth type to register as related to the target union type.</typeparam>
    [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
    sealed partial class RelationAttribute<T0, T1, T2, T3, T4, T5, T6, T7> : Attribute
    { }
}

// <auto-generated>
// This file was generated by RhoMicro.CodeAnalysis.UnionsGenerator
// The tool used to generate this code may be subject to license terms;
// this generated code is however not subject to those terms, instead it is
// subject to the license (if any) applied to the containing project.
// </auto-generated>
#nullable enable
#pragma warning disable

namespace RhoMicro.CodeAnalysis
{
    using System;

    /// <summary>
    /// Marks the target method as the factory method to use when instantiating 
    /// an instance of the union type representing a value of the annotated parameter.
    /// Factory methods must be static, have no type parameters and only have one 
    /// parameter of a type representable by the union type. 
    /// Factory polymorphism is not yet supported.
    /// </summary>
    [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
#if UNIONS_GENERATOR
    [GenerateFactory]
#endif
    sealed partial class UnionTypeFactoryAttribute : Attribute
    { }
}

// <auto-generated>
// This file was generated by RhoMicro.CodeAnalysis.UnionsGenerator
// The tool used to generate this code may be subject to license terms;
// this generated code is however not subject to those terms, instead it is
// subject to the license (if any) applied to the containing project.
// </auto-generated>
#nullable enable
#pragma warning disable

namespace RhoMicro.CodeAnalysis.UnionsGenerator.Generated
{
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Text;
    using System.Linq;
    using System;

    [System.CodeDom.Compiler.GeneratedCodeAttribute("RhoMicro.CodeAnalysis.UnionsGenerator", "14.0.2.0")]
    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
    internal static class Util
    {
        private readonly static ConcurrentDictionary<Type, String> _cache = new();
        internal static String GetFullString(Type type) => _cache.GetOrAdd(type, ValueFactory);
        static String ValueFactory(Type type)
        {
            var result = getString(type, new());

            return result;

            static String getString(Type type, StringBuilder builder)
            {
                var unboundTransitiveParameters = 0;
                var transitiveParameters = new List<(String Format, Type? Argument)>();
                append(type, builder, transitiveParameters, ref unboundTransitiveParameters);
                var result = builder.ToString();

                for(var i = 0; i < transitiveParameters.Count; i++)
                {
                    _ = builder.Clear();
                    var (format, argument) = transitiveParameters[i];
                    var replacement = getString(argument!, builder);
                    result = result.Replace(format, replacement);
                }

                return result;

                static void append(
                    Type type,
                    StringBuilder builder,
                    List<(String Format, Type? Argument)> transitiveArgumentsMap,
                    ref Int32 unboundTransitiveParameters)
                {
#if NETSTANDARD2_0
                        if(type.IsGenericParameter && type.DeclaringMethod is null)
#else
                    if(type.IsGenericTypeParameter)
#endif
                    {
                        var format = $"{Guid.NewGuid()}";
                        _ = builder.Append(format);
                        transitiveArgumentsMap.Add((format, null));
                        unboundTransitiveParameters++;
                        return;
                    } else if(type.DeclaringType != null)
                    {
                        append(type.DeclaringType, builder, transitiveArgumentsMap, ref unboundTransitiveParameters);
                        _ = builder.Append('.');
                    } else if(type.Namespace != null)
                    {
                        _ = builder.Append(type.Namespace)
                                .Append('.');
                    }

                    var tickIndex = type.Name.IndexOf('`');
                    _ = tickIndex != -1 ?
#if NETSTANDARD2_0
                            builder.Append(type.Name.Substring(0, tickIndex)) :
#else
                        builder.Append(type.Name.AsSpan(0, tickIndex)) :
#endif
                        builder.Append(type.Name);

                    var arguments = type.GetGenericArguments();
                    var inflectionPoint = unboundTransitiveParameters;
                    if(arguments.Length > 0 && unboundTransitiveParameters > 0)
                    {
                        for(; unboundTransitiveParameters > 0;)
                        {
                            unboundTransitiveParameters--;
                            var (format, _) = transitiveArgumentsMap[unboundTransitiveParameters];
                            transitiveArgumentsMap[unboundTransitiveParameters] = (format, arguments[unboundTransitiveParameters]);
                        }
                    }

                    if(arguments.Length > inflectionPoint)
                    {
                        _ = builder.Append('<');
                        append(arguments[inflectionPoint], builder, transitiveArgumentsMap, ref unboundTransitiveParameters);

                        for(var i = inflectionPoint + 1; i < type.GenericTypeArguments.Length; i++)
                        {
                            _ = builder.Append(", ");
                            append(arguments[i], builder, transitiveArgumentsMap, ref unboundTransitiveParameters);
                        }

                        _ = builder.Append('>');
                    }
                }
            }
        }
        
        internal static System.Boolean IsMarked(Type type) =>
            type.CustomAttributes.Any(a => a.AttributeType.FullName == "RhoMicro.CodeAnalysis.UnionTypeAttribute") ||
            type.GenericTypeArguments.Any(t => t.CustomAttributes.Any(a => 
                a.AttributeType.FullName.StartsWith("RhoMicro.CodeAnalysis.UnionTypeAttribute`") 
                && a.AttributeType.GenericTypeArguments.Length < 255));

        private static readonly System.Collections.Concurrent.ConcurrentDictionary<(Type, Type), Object> _conversionImplementations = new();
        internal static TTo UnsafeConvert<TFrom, TTo>(in TFrom from)
        {
            var impl = (System.Func<TFrom, TTo>)_conversionImplementations.GetOrAdd((typeof(TFrom), typeof(TTo)), k =>
            {
                var param = System.Linq.Expressions.Expression.Parameter(k.Item1);
                var castExpr = System.Linq.Expressions.Expression.Convert(param, k.Item2);
                var lambda = System.Linq.Expressions.Expression.Lambda(castExpr, param).Compile();

                return lambda;
            });
            var result = impl.Invoke(from);

            return result;
        }
    }
}
// <auto-generated>
// This file was generated by RhoMicro.CodeAnalysis.UnionsGenerator
// The tool used to generate this code may be subject to license terms;
// this generated code is however not subject to those terms, instead it is
// subject to the license (if any) applied to the containing project.
// </auto-generated>
#nullable enable
#pragma warning disable

namespace RhoMicro.CodeAnalysis
{
    using System;
    using System.Collections.Generic;

    /// <summary>
    /// Defines options for generating union types.
    /// </summary>
    [Flags]
    enum UnionTypeOptions
    {
        /// <summary>
        /// The default options.
        /// </summary>
        Default = ImplicitConversionIfSolitary,
        /// <summary>
        /// </summary>
        None = 0x00,
        /// <summary>
        /// Instructs the generator to emit an implicit conversion to the representable type if it is the only one.
        /// In effect, this option will enable the union type to act as an alias wrapper for the representable type.
        /// </summary>
        ImplicitConversionIfSolitary = 0x01,
        /// <summary>
        /// Instructs the generator to emit a superset conversion operator implementation even though
        /// the representable type is a generic type parameter. By default, it is omitted because of possible
        /// unification for certain generic arguments.
        /// </summary>
        //SupersetOfParameter = 0x02,
        /// <summary>
        /// Instructs the generator to treat the representable reference type 
        /// as nullable, allowing for <see langword="null"/> 
        /// arguments in factories, conversions etc.
        /// </summary>
        Nullable = 0x04
    }

    /// <summary>
    /// Defines options for the storage implementation of a representable type.
    /// In order for the generator to generate an efficient storage implementation, 
    /// consumers should communicate whether the representable type is known to
    /// be a struct, class or of unknown nature. This is mostly relevant for generic
    /// type parameters, however an explicit strategy may be selected for any representable
    /// type. Whether or not generic type parameters are known to be reference
    /// or value types depends on their constraints. Parameters constrained to 
    /// <see langword="struct"/> will be assumed to be value types. Conversely,
    /// parameters constrained to <see langword="class"/> will be assumed to be reference types.
    /// </summary>
    /*
               | box |value| auto | field
        struct | rc! | vc  | vc   | cc
        class  | rc  | rc! | rc   | cc
        none   | rc! | vc! | rc!  | cc
    */
    enum StorageOption
    {
        /// <summary>
        /// The generator will automatically decide on a storage strategy.
        /// <para>
        /// If the representable type is <b>known to be a value type</b>,
        /// this will store values of that type inside a shared value type container.
        /// <b>Boxing will not occur.</b>
        /// </para>
        /// <para>
        /// If the representable type is <b>known to be a reference type</b>,
        /// this will store values of that type inside a shared reference type container.
        /// </para>
        /// <para>
        /// If the representable type is <b>neither known to be a reference type
        /// nor a value type</b>, this option will cause values of that type to 
        /// be stored inside a shared reference type container.
        /// <b>If the representable type is a generic type parameter,
        /// boxing will occur for value type arguments to that parameter.</b>
        /// </para>
        /// </summary>
        Auto,

        /// <summary>
        /// The generator will always store values of the representable type
        /// inside a shared reference type container.
        /// <para>
        /// If the representable type is <b>known to be a value type</b>,
        /// <b>boxing will occur</b>.
        /// </para>
        /// <para>
        /// If the representable type is a <b>generic type parameter</b>,
        /// <b>boxing will occur for value type arguments</b> to that parameter.
        /// </para>
        /// </summary>
        Reference,

        /// <summary>
        /// The generator will attempt to store values of the representable type
        /// inside a value type container.
        /// <para>
        /// If the representable type is <b>known to be a value type</b>,
        /// this will store values of that type inside a shared value type container.
        /// <b>Boxing will not occur.</b>
        /// </para>
        /// <para>
        /// If the representable type is <b>known to be a reference type</b>,
        /// this will store values of that type inside a shared reference type container.
        /// <b>Boxing will not occur.</b>
        /// </para>
        /// <para>
        /// If the representable type is <b>neither known to be a reference type
        /// nor a value type</b>, this option will cause values of that type to 
        /// be stored inside a shared value type container.
        /// <b>If the representable type is a generic type parameter,
        /// an exception of type <see cref="TypeLoadException"/> will occur for
        /// reference type arguments to that parameter.</b>
        /// </para>
        /// </summary>
        Value,

        /// <summary>
        /// The generator will attempt to store values of the representable type
        /// inside a dedicated container for that type.
        /// <para>
        /// If the representable type is <b>known to be a value type</b>,
        /// this will store values of that type inside a dedicated 
        /// value type container.
        /// <b>Boxing will not occur.</b>
        /// </para>
        /// <para>
        /// If the representable type is <b>known to be a reference type</b>,
        /// this will store values of that type inside a 
        /// dedicated reference type container.
        /// </para>
        /// <para>
        /// If the representable type is <b>neither known to be a reference type
        /// nor a value type</b>, this option will cause values of that type to 
        /// be stored inside a dedicated strongly typed container.
        /// <b>Boxing will not occur.</b>
        /// </para>
        /// </summary>
        Field
    }

    /// <summary>
    /// Marks the target type as a union type being able to represent the type passed to the constructor.
    /// </summary>
    [AttributeUsage(( (AttributeTargets)( -1 ) ))]
    partial class UnionTypeBaseAttribute : Attribute
    {
        /// <summary>
        /// Gets or sets the alias groups that the representable type is to be a part of. 
        /// Represnetable types that share a group may be checked for using unified methods 
        /// and properties like <c>IsGroup</c> where <c>Group</c> is the name of the group
        /// that the representable type is a part of.
        /// </summary>
        public virtual String[] Groups { get; set; } = Array.Empty<String>();

        /// <summary>
        /// Gets or sets the generator options to use.
        /// </summary>
        public virtual UnionTypeOptions Options { get; set; } = UnionTypeOptions.Default;

        /// <summary>
        /// Gets or sets the option defining storage generation.
        /// </summary>
        public virtual StorageOption Storage { get; set; }
    }
    [AttributeUsage(( (AttributeTargets)( -1 ) ))]
#if UNIONS_GENERATOR
    [GenerateFactory(OmitTypeCheck = true)]
#endif
    partial class AliasedUnionTypeBaseAttribute : UnionTypeBaseAttribute
    {
        /// <summary>
        /// Gets or sets the alias to use for members representing the type represented by the union.
        /// For example, the represented type <see cref="List{T}"/> would be represented using names like
        /// <c>list_of_T</c>. Setting this property to <c>yourAlias</c> will instruct the generator to use
        /// member names like <c>yourAlias</c> instead of <c>list_of_T</c>. Use this property to avoid
        /// name collisions in generated code. Since the alias will be used for member names, it will
        /// only be taken into account if it is a valid identifier name.
        /// </summary>
        public String? Alias { get; set; }
        /// <inheritdoc/>
        public override String[] Groups { get => base.Groups; set => base.Groups = value; }
        /// <inheritdoc/>
        public override UnionTypeOptions Options { get => base.Options; set => base.Options = value; }
        /// <inheritdoc/>
        public override StorageOption Storage { get => base.Storage; set => base.Storage = value; }
    }
    /// <summary>
    /// Marks the target type as a union type being able to represent <typeparamref name="T0"/>.
    /// </summary>
    [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
    sealed partial class UnionTypeAttribute<T0> : AliasedUnionTypeBaseAttribute
    { }
    /// <summary>
    /// Marks the target type as a union type being able to represent 
    /// <typeparamref name="T0"/>
    /// and <typeparamref name="T1"/>.
    /// </summary>
    [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
    sealed partial class UnionTypeAttribute<T0, T1> : UnionTypeBaseAttribute
    { }
    /// <summary>
    /// Marks the target type as a union type being able to represent 
    /// <typeparamref name="T0"/>,
    /// <typeparamref name="T1"/>
    /// and <typeparamref name="T2"/>.
    /// </summary>
    [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
    sealed partial class UnionTypeAttribute<T0, T1, T2> : UnionTypeBaseAttribute
    { }
    /// <summary>
    /// Marks the target type as a union type being able to represent 
    /// <typeparamref name="T0"/>,
    /// <typeparamref name="T1"/>,
    /// <typeparamref name="T2"/>
    /// and <typeparamref name="T3"/>.
    /// </summary>
    [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
    sealed partial class UnionTypeAttribute<T0, T1, T2, T3> : UnionTypeBaseAttribute
    { }
    /// <summary>
    /// Marks the target type as a union type being able to represent 
    /// <typeparamref name="T0"/>,
    /// <typeparamref name="T1"/>,
    /// <typeparamref name="T2"/>,
    /// <typeparamref name="T3"/>
    /// and <typeparamref name="T4"/>.
    /// </summary>
    [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
    sealed partial class UnionTypeAttribute<T0, T1, T2, T3, T4> : UnionTypeBaseAttribute
    { }
    /// <summary>
    /// Marks the target type as a union type being able to represent 
    /// <typeparamref name="T0"/>,
    /// <typeparamref name="T1"/>,
    /// <typeparamref name="T2"/>,
    /// <typeparamref name="T3"/>,
    /// <typeparamref name="T4"/>
    /// and <typeparamref name="T5"/>.
    /// </summary>
    [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
    sealed partial class UnionTypeAttribute<T0, T1, T2, T3, T4, T5> : UnionTypeBaseAttribute
    { }
    /// <summary>
    /// Marks the target type as a union type being able to represent 
    /// <typeparamref name="T0"/>,
    /// <typeparamref name="T1"/>,
    /// <typeparamref name="T2"/>,
    /// <typeparamref name="T3"/>,
    /// <typeparamref name="T4"/>,
    /// <typeparamref name="T5"/>
    /// and <typeparamref name="T6"/>.
    /// </summary>
    [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
    sealed partial class UnionTypeAttribute<T0, T1, T2, T3, T4, T5, T6> : UnionTypeBaseAttribute
    { }
    /// <summary>
    /// Marks the target type as a union type being able to represent 
    /// <typeparamref name="T0"/>,
    /// <typeparamref name="T1"/>,
    /// <typeparamref name="T2"/>,
    /// <typeparamref name="T3"/>,
    /// <typeparamref name="T4"/>,
    /// <typeparamref name="T5"/>,
    /// <typeparamref name="T6"/>
    /// and <typeparamref name="T7"/>.
    /// </summary>
    [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
    sealed partial class UnionTypeAttribute<T0, T1, T2, T3, T4, T5, T6, T7> : UnionTypeBaseAttribute
    { }
    /// <summary>
    /// Marks the target type as a union type being able to represent the annotated type parameter.
    /// </summary>
    [AttributeUsage(AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
    sealed partial class UnionTypeAttribute : AliasedUnionTypeBaseAttribute
    { }
}
// <auto-generated>
// This file was generated by RhoMicro.CodeAnalysis.UnionsGenerator
// The tool used to generate this code may be subject to license terms;
// this generated code is however not subject to those terms, instead it is
// subject to the license (if any) applied to the containing project.
// </auto-generated>
#nullable enable
#pragma warning disable

namespace RhoMicro.CodeAnalysis;

using System;

#region Setting Enums
/// <summary>
/// Defines settings for generating an implementation of <see cref="Object.ToString"/>.
/// </summary>
enum ToStringSetting
{
    /// <summary>
    /// The generator will emit an implementation that returns detailed information, including:
    /// <list type="bullet">
    /// <item><description>the name of the union type</description></item>
    /// <item><description>a list of types representable by the union type</description></item>
    /// <item><description>an indication of which type is being represented by the instance</description></item>
    /// <item><description>the value currently being represented by the instance</description></item>
    /// </list>
    /// </summary>
    Detailed,
    /// <summary>
    /// The generator will not generate an implementation of <see cref="Object.ToString"/>.
    /// </summary>
    None,
    /// <summary>
    /// The generator will generate an implementation that returns the result of calling <see cref="Object.ToString"/> on the currently represented value.
    /// </summary>
    Simple
}
/// <summary>
/// Defines settings for annotating the target with an instance of <see cref="System.Runtime.InteropServices.StructLayoutAttribute"/>.
/// </summary>
enum LayoutSetting
{
    /// <summary>
    /// Generate an annotation optimized for size.
    /// </summary>
    Small,
    /// <summary>
    /// Do not generate any annotations.
    /// </summary>
    Auto
}
/// <summary>
/// Defines settings for controlling the accessibility of generated constructors.
/// </summary>
enum ConstructorAccessibilitySetting
{
    /// <summary>
    /// Generated constructors should always be private, unless
    /// no conversion operators are generated for the type they
    /// accept. This would be the case for interface types or
    /// supertypes of the target union.
    /// </summary>
    PublicIfInconvertible,
    /// <summary>
    /// Generated constructors should always be private.
    /// </summary>
    Private,
    /// <summary>
    /// Generated constructors should always be public
    /// </summary>
    Public
}
/// <summary>
/// Defines settings on how to implement interfaces that all representable
/// types implement.
/// </summary>
enum InterfaceMatchSetting
{
    /// <summary>
    /// Generated interface implementations should be explicit if at least
    /// one of the representable types implements the interface explicitly;
    /// otherwise, interface implementations should be implicit.
    /// </summary>
    Auto,
    /// <summary>
    /// Generated interface implementations should always be explicit.
    /// </summary>
    Explicit,
    /// <summary>
    /// Generated interface implementations should always be implicit.
    /// </summary>
    Implicit,
    /// <summary>
    /// No interfaces implementations should be generated.
    /// </summary>
    Omit
}
/// <summary>
/// Defines settings for the kind of diagnostics to report.
/// </summary>
[Flags]
enum DiagnosticsLevelSettings
{
    /// <summary>
    /// Instructs the analyzer not to emit diagnostics
    /// </summary>
    None = 0x00,
    /// <summary>
    /// Instructs the analyzer to report info diagnostics.
    /// </summary>
    Info = 0x01,
    /// <summary>
    /// Instructs the analyzer to report warning diagnostics.
    /// </summary>
    Warning = 0x02,
    /// <summary>
    /// Instructs the analyzer to report error diagnostics.
    /// </summary>
    Error = 0x04,
    /// <summary>
    /// Instructs the analyzer to report all diagnostics.
    /// </summary>
    All = Info | Warning | Error
}
/// <summary>
/// Defines miscellaneous settings.
/// </summary>
[Flags]
enum MiscellaneousSettings
{
    /// <summary>
    /// </summary>
    None = 0x00,
    /// <summary>
    /// The default settings.
    /// </summary>
    Default = None,
    /// <summary>
    /// Indicates whether the generated source code should be available as a string constant on the union type itself.
    /// This setting is generally only useful if the generated implementation should be emitted from another generator.
    /// </summary>
    EmitGeneratedSourceCode = 0x01,
    /// <summary>
    /// Indicates whether to generate a custom converter type 
    /// for <c>System.Text.Json</c> deserialization. If set, this will also cause
    /// the union type to be annotated with an appropriate <c>JsonConverter</c> attribute.
    /// </summary>
    GenerateJsonConverter = 0x02,
    /// <summary>
    /// Indicates that the generator should emit a comment detailing the structure of the union type.
    /// </summary>
    EmitStructuralRepresentation = 0x04
}

/// <summary>
/// Defines settings pertaining to equality operator implementations.
/// </summary>
enum EqualityOperatorsSetting
{
    /// <summary>
    /// Equality operators will be emitted only if the target union type is a value type.
    /// </summary>
    EmitOperatorsIfValueType,
    /// <summary>
    /// Equality operators will be emitted.
    /// </summary>
    EmitOperators,
    /// <summary>
    /// Equality operators will be omitted.
    /// </summary>
    OmitOperators
}

#endregion
#region Attribute Declaration
/// <summary>
/// Supplies the generator with additional settings on how to generate a targeted union type.
/// If the target member is an assembly, the attribute supplies default values for any union 
/// type setting not defined.
/// </summary>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = false, Inherited = false)]
#if UNIONS_GENERATOR
[GenerateFactory]
#endif
sealed partial class UnionTypeSettingsAttribute : Attribute
{
    #region Settings
    /// <summary>
    /// Defines how to generate an implementation <see cref="Object.ToString"/>.
    /// </summary>
    public ToStringSetting ToStringSetting { get; set; } = ToStringSetting.Detailed;
    /// <summary>
    /// Defines whether to generate a size optimizing annotation.
    /// </summary>
    public LayoutSetting Layout { get; set; } = LayoutSetting.Auto;
    /// <summary>
    /// The level of diagnostics to be reported by the analyzer.
    /// </summary>
    public DiagnosticsLevelSettings DiagnosticsLevel { get; set; } = DiagnosticsLevelSettings.All;
    /// <summary>
    /// The desired accessibility of generated constructors.
    /// </summary>
    public ConstructorAccessibilitySetting ConstructorAccessibility { get; set; } = ConstructorAccessibilitySetting.Private;
    /// <summary>
    /// Indicates how to generate implementations for
    /// interfaces implemented by all representable types. Implementations will 
    /// map calls to interface instance methods and properties onto the represented
    /// value. 
    /// <para>
    /// Please note that currently, only fully bound and constructed interface implementations are supported.
    /// </para>
    /// </summary>
    public InterfaceMatchSetting InterfaceMatchSetting { get; set; } = InterfaceMatchSetting.Auto;
    /// <summary>
    /// Indicates how to generate equality operators.
    /// By default, equality operators will only be emitted for value types, so as to preserve
    /// reference equality for comparing reference union types via <c>==</c> or <c>!=</c>.
    /// </summary>
    public EqualityOperatorsSetting EqualityOperatorsSetting { get; set; } = EqualityOperatorsSetting.EmitOperatorsIfValueType;
    /// <summary>
    /// Gets or sets miscellaneous settings.
    /// </summary>
    public MiscellaneousSettings Miscellaneous { get; set; } = MiscellaneousSettings.Default;
    #endregion
    #region Strings
    /// <summary>
    /// A raw code preface to prepend before the generated type declaration.
    /// </summary>
    public String TypeDeclarationPreface { get; set; } = "";
    /// <summary>
    /// The name of the generic parameter for generic <c>Is</c>, <c>As</c> and factory methods. 
    /// Set this property in order to avoid name collisions with generic union type parameters
    /// </summary>
    public String GenericTValueName { get; set; } = "TValue";
    /// <summary>
    /// The name of the generic parameter for the <c>TryConvert</c> method. 
    /// Set this property in order to avoid name collisions with generic union type parameters
    /// </summary>
    public String TryConvertTypeName { get; set; } = "TUnion";
    /// <summary>
    /// The name of the generic parameter for the <c>Match</c> method. 
    /// Set this property in order to avoid name collisions with generic union type parameters
    /// </summary>
    public String MatchTypeName { get; set; } = "TMatchResult";
    /// <summary>
    /// The name to use for the discriminating tag type.
    /// </summary>
    public String TagTypeName { get; set; } = "__Tag";
    /// <summary>
    /// The name to use for the container type containing value types.
    /// </summary>
    public String ValueTypeContainerTypeName { get; set; } = "__ValueTypeContainer";
    /// <summary>
    /// The name to use for the field containing value types.
    /// </summary>
    public String ValueTypeContainerName { get; set; } = "__value";
    /// <summary>
    /// The name to use for the field containing reference types.
    /// </summary>
    public String ReferenceTypeContainerName { get; set; } = "__reference";
    /// <summary>
    /// The name to use for the field containing the discriminating tag.
    /// </summary>
    public String TagFieldName { get; set; } = "__tag";
    /// <summary>
    /// The name to use for the default (uninitialized) tag value.
    /// </summary>
    public String TagNoneName { get; set; } = "__None";
    /// <summary>
    /// The name of the generated json converter type.
    /// </summary>
    public String JsonConverterTypeName { get; set; } = "JsonConverter";
    #endregion
}
#endregion
// <auto-generated>
// This file was last generated by RhoMicro.CodeAnalysis.UnionsGenerator at 2/18/2024 10:51:57 AM +02:00
// The tool used to generate this code may be subject to license terms;
// this generated code is however not subject to those terms, instead it is
// subject to the license (if any) applied to the containing project.
// </auto-generated>
#pragma warning disable
#nullable enable
#region Implementation of UnionTypesDemo.ResultSave
namespace UnionTypesDemo
{
	using System.Linq;
	
	#region Scoped Data
	file static class UnionTypesDemo_ResultSave_ScopedData
	{
		public static System.Collections.Concurrent.ConcurrentDictionary<System.Type, System.Object> Cache { get; } = new();
		public static System.Collections.Generic.HashSet<System.Type> RepresentableTypes { get; } = 
		new ()
		{
			typeof(UnionTypesDemo.Success),
			typeof(UnionTypesDemo.ValidationError)
		}
		;
	}
	#endregion
	partial class ResultSave : System.IEquatable<ResultSave?>
	{
		
		#region Nested Types
		#region Value Type Container
		#endregion
		#region Tag Type
		/// <summary>
		/// Defines tags to discriminate between representable types.
		/// </summary>
		/// <remarks>
		/// This member is not intended for use by user code inside of or any code outside of <see cref="UnionTypesDemo.ResultSave"/>.
		/// </remarks>
		[System.CodeDom.Compiler.GeneratedCodeAttribute("RhoMicro.CodeAnalysis.UnionsGenerator", "14.0.2.0")]
		[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
		private enum __Tag : System.Byte
		{
			/// <summary>
			/// Used when not representing any type due to e.g. incorrect or missing initialization.
			/// </summary>
			__None,

			
			/// <summary>
			/// Used when representing an instance of <see cref="UnionTypesDemo.Success"/>.
			/// </summary>
			Success,
			
			/// <summary>
			/// Used when representing an instance of <see cref="UnionTypesDemo.ValidationError"/>.
			/// </summary>
			ValidationError
		}
		#endregion
		#endregion
		
		#region Constructors
		
		/// <summary>
		/// Creates a new instance of <see cref="UnionTypesDemo.ResultSave"/>representing an instance of <see cref="UnionTypesDemo.Success"/>.
		/// </summary>
		[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
		[System.CodeDom.Compiler.GeneratedCodeAttribute("RhoMicro.CodeAnalysis.UnionsGenerator", "14.0.2.0")]
		private ResultSave(UnionTypesDemo.Success value)
		{
			__tag = __Tag.Success;
			this.__reference = value;
		}
		
		
		/// <summary>
		/// Creates a new instance of <see cref="UnionTypesDemo.ResultSave"/>representing an instance of <see cref="UnionTypesDemo.ValidationError"/>.
		/// </summary>
		[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
		[System.CodeDom.Compiler.GeneratedCodeAttribute("RhoMicro.CodeAnalysis.UnionsGenerator", "14.0.2.0")]
		private ResultSave(UnionTypesDemo.ValidationError value)
		{
			__tag = __Tag.ValidationError;
			this.__reference = value;
		}
		#endregion
		
		#region Fields
		
		/// <summary>
		/// Contains the value of instances of <see cref="UnionTypesDemo.ResultSave"/> representing one of these types:
		/// <list type="bullet">
		/// <item>
		/// <see cref="UnionTypesDemo.Success"/>
		/// </item>
		/// <item>
		/// <see cref="UnionTypesDemo.ValidationError"/>
		/// </item>
		/// </list>
		/// </summary>
		/// <remarks>
		/// This member is not intended for use by user code inside of or any code outside of <see cref="UnionTypesDemo.ResultSave"/>.
		/// </remarks>
		[System.CodeDom.Compiler.GeneratedCodeAttribute("RhoMicro.CodeAnalysis.UnionsGenerator", "14.0.2.0")]
		[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
		private readonly System.Object? __reference;
		
		/// <summary>
		/// Used to determine the currently represented type and value.
		/// </summary>
		/// <remarks>
		/// This member is not intended for use by user code inside of or any code outside of <see cref="UnionTypesDemo.ResultSave"/>.
		/// </remarks>
		[System.CodeDom.Compiler.GeneratedCodeAttribute("RhoMicro.CodeAnalysis.UnionsGenerator", "14.0.2.0")]
		[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
		private readonly __Tag __tag;
		#endregion
		
		#region Factories
		
		/// <summary>
		/// Creates a new instance of <see cref="UnionTypesDemo.ResultSave"/> representing an instance of <see cref="UnionTypesDemo.Success"/>.
		/// </summary>
		/// <param name="value">
		/// The value to be represented by the new instance of <see cref="UnionTypesDemo.ResultSave"/>.
		/// </param>
		/// <returns>
		/// A new instance of <see cref="UnionTypesDemo.ResultSave"/> representing <paramref name="value"/>.
		/// </returns>
		public static ResultSave CreateFromSuccess([RhoMicro.CodeAnalysis.UnionTypeFactory]UnionTypesDemo.Success value) => new(value);
		
		/// <summary>
		/// Creates a new instance of <see cref="UnionTypesDemo.ResultSave"/> representing an instance of <see cref="UnionTypesDemo.ValidationError"/>.
		/// </summary>
		/// <param name="value">
		/// The value to be represented by the new instance of <see cref="UnionTypesDemo.ResultSave"/>.
		/// </param>
		/// <returns>
		/// A new instance of <see cref="UnionTypesDemo.ResultSave"/> representing <paramref name="value"/>.
		/// </returns>
		public static ResultSave CreateFromValidationError([RhoMicro.CodeAnalysis.UnionTypeFactory]UnionTypesDemo.ValidationError value) => new(value);
		/// <summary>
		/// Attempts to create an instance of <see cref="UnionTypesDemo.ResultSave"/> from an instance of <typeparamref name="TValue"/>.
		/// </summary>
		/// <param name="value">
		/// The value from which to attempt to create an instance of <see cref="UnionTypesDemo.ResultSave"/>.
		/// </param>
		/// <param name="result">
		/// If an instance of <see cref="UnionTypesDemo.ResultSave"/> could successfully be created, this parameter will contain the newly created instance; otherwise, <see langword="default"/>.
		/// </param>
		/// <returns>
		/// <see langword="true"/> if an instance of <see cref="UnionTypesDemo.ResultSave"/> could successfully be created; otherwise, <see langword="false"/>.
		/// </returns>
		public static System.Boolean TryCreate<TValue>(TValue value, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out ResultSave? result)
		{
			var metadataName = RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.GetFullString(typeof(TValue));
			switch(metadataName)
			{
				case "UnionTypesDemo.Success":
				{
					result = CreateFromSuccess((RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.UnsafeConvert<TValue, UnionTypesDemo.Success>(value)));
					return true;
				}
				
				case "UnionTypesDemo.ValidationError":
				{
					result = CreateFromValidationError((RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.UnsafeConvert<TValue, UnionTypesDemo.ValidationError>(value)));
					return true;
				}
				default:
				{
					
					{
						var sourceType = typeof(TValue);
						if(!UnionTypesDemo_ResultSave_ScopedData.Cache.TryGetValue(sourceType, out var weakMatch))
						{
							if(!RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.IsMarked(sourceType))
							{
								result = default;
								return false;
							}
							weakMatch = UnionTypesDemo_ResultSave_ScopedData.Cache.GetOrAdd(sourceType, t =>
							{
								var tupleType = typeof(System.ValueTuple<System.Boolean, ResultSave>);
								var matchMethod = sourceType.GetMethod(nameof(Match), System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public)
									?.MakeGenericMethod(tupleType) ??
									throw new System.InvalidOperationException("Unable to locate match function on source union type. This indicates a bug in the marker detection algorithm.");
								var targetFactoryMap = typeof(UnionTypesDemo.ResultSave).GetMethods()
									.Where(c => c.CustomAttributes.Any(a => a.AttributeType.FullName == "RhoMicro.CodeAnalysis.UnionTypeFactoryAttribute"))
									.ToDictionary(c => c.GetParameters()[0].ParameterType);
								var handlers = matchMethod.GetParameters()
									.Select(p => p.ParameterType.GenericTypeArguments[0])
									.Select(t => (ParameterExpr: System.Linq.Expressions.Expression.Parameter(t), ParameterExprType: t))
									.Select(t =>
									{
										var delegateType = typeof(System.Func<,>).MakeGenericType(t.ParameterExprType, tupleType);
										System.Linq.Expressions.Expression expression = targetFactoryMap.TryGetValue(t.ParameterExprType, out var factory)
											? System.Linq.Expressions.Expression.New(tupleType.GetConstructors()[0], System.Linq.Expressions.Expression.Constant(true), System.Linq.Expressions.Expression.Call(factory, t.ParameterExpr))
											: System.Linq.Expressions.Expression.Default(tupleType);
										return System.Linq.Expressions.Expression.Lambda(delegateType, expression, t.ParameterExpr);
									}
									);var paramExpr = System.Linq.Expressions.Expression.Parameter(sourceType);
								var callExpr = System.Linq.Expressions.Expression.Call(paramExpr, matchMethod, handlers);
								var lambdaExpr = System.Linq.Expressions.Expression.Lambda(callExpr, paramExpr);
								var result = lambdaExpr.Compile();
								return result;
							}
							);
						}
						var match = (System.Func<TValue, (System.Boolean, UnionTypesDemo.ResultSave)>)weakMatch;
						var matchResult = match.Invoke(value);
						if(!matchResult.Item1)
						{
							result = default;
							return false;
						}
						result = matchResult.Item2;
						return true;
					}
				}
			}
		}
		/// <summary>
		/// Creates an instance of <see cref="UnionTypesDemo.ResultSave"/> from an instance of <typeparamref name="TValue"/>.
		/// </summary>
		/// <param name="value">
		/// The value from which to create an instance of <see cref="UnionTypesDemo.ResultSave"/>.
		/// </param>
		/// <returns>
		/// A new instance of <see cref="UnionTypesDemo.ResultSave"/> representing <paramref name="value"/>.
		/// </returns>
		public static ResultSave Create<TValue>(TValue value)
		{
			var metadataName = RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.GetFullString(typeof(TValue));
			switch(metadataName)
			{
				case "UnionTypesDemo.Success":
				{
					return CreateFromSuccess((RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.UnsafeConvert<TValue, UnionTypesDemo.Success>(value)));
				}
				
				case "UnionTypesDemo.ValidationError":
				{
					return CreateFromValidationError((RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.UnsafeConvert<TValue, UnionTypesDemo.ValidationError>(value)));
				}
				default:
				{
					
					{
						var sourceType = typeof(TValue);
						if(!UnionTypesDemo_ResultSave_ScopedData.Cache.TryGetValue(sourceType, out var weakMatch))
						{
							if(!RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.IsMarked(sourceType))
							{
								throw new System.InvalidOperationException($"Unable to create an instance of UnionTypesDemo.ResultSave from an instance of {typeof(TValue)}.");
							}
							weakMatch = UnionTypesDemo_ResultSave_ScopedData.Cache.GetOrAdd(sourceType, t =>
							{
								var tupleType = typeof(System.ValueTuple<System.Boolean, ResultSave>);
								var matchMethod = sourceType.GetMethod(nameof(Match), System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public)
									?.MakeGenericMethod(tupleType) ??
									throw new System.InvalidOperationException("Unable to locate match function on source union type. This indicates a bug in the marker detection algorithm.");
								var targetFactoryMap = typeof(UnionTypesDemo.ResultSave).GetMethods()
									.Where(c => c.CustomAttributes.Any(a => a.AttributeType.FullName == "RhoMicro.CodeAnalysis.UnionTypeFactoryAttribute"))
									.ToDictionary(c => c.GetParameters()[0].ParameterType);
								var handlers = matchMethod.GetParameters()
									.Select(p => p.ParameterType.GenericTypeArguments[0])
									.Select(t => (ParameterExpr: System.Linq.Expressions.Expression.Parameter(t), ParameterExprType: t))
									.Select(t =>
									{
										var delegateType = typeof(System.Func<,>).MakeGenericType(t.ParameterExprType, tupleType);
										System.Linq.Expressions.Expression expression = targetFactoryMap.TryGetValue(t.ParameterExprType, out var factory)
											? System.Linq.Expressions.Expression.New(tupleType.GetConstructors()[0], System.Linq.Expressions.Expression.Constant(true), System.Linq.Expressions.Expression.Call(factory, t.ParameterExpr))
											: System.Linq.Expressions.Expression.Default(tupleType);
										return System.Linq.Expressions.Expression.Lambda(delegateType, expression, t.ParameterExpr);
									}
									);var paramExpr = System.Linq.Expressions.Expression.Parameter(sourceType);
								var callExpr = System.Linq.Expressions.Expression.Call(paramExpr, matchMethod, handlers);
								var lambdaExpr = System.Linq.Expressions.Expression.Lambda(callExpr, paramExpr);
								var result = lambdaExpr.Compile();
								return result;
							}
							);
						}
						var match = (System.Func<TValue, (System.Boolean, UnionTypesDemo.ResultSave)>)weakMatch;
						var matchResult = match.Invoke(value);
						if(!matchResult.Item1)
						{
							throw new System.InvalidOperationException($"Unable to create an instance of UnionTypesDemo.ResultSave from an instance of {typeof(TValue)}.");
						}
						return matchResult.Item2;
					}
				}
			}
		}
		#endregion
		
		#region Switch
		/// <summary>
		/// Invokes a handler based on the type of value being represented.
		/// </summary>
		/// <param name="onSuccess">
		/// The handler to invoke if the union is currently representing an instance of <see cref="UnionTypesDemo.Success"/>.
		/// </param>
		/// <param name="onValidationError">
		/// The handler to invoke if the union is currently representing an instance of <see cref="UnionTypesDemo.ValidationError"/>.
		/// </param>
		public void Switch(
			System.Action<UnionTypesDemo.Success> onSuccess,
			System.Action<UnionTypesDemo.ValidationError> onValidationError)
		{
			switch(this.__tag)
			{
				case __Tag.Success:
				{
					onSuccess.Invoke(((UnionTypesDemo.Success)this.__reference!));
					return;
				}
				
				case __Tag.ValidationError:
				{
					onValidationError.Invoke(((UnionTypesDemo.ValidationError)this.__reference!));
					return;
				}
				
				default:
				{
					throw new System.InvalidOperationException("Unable to determine the represented type or value. The union type was likely not initialized correctly.");
				}
			}
		}
		#endregion
		
		#region Match
		/// <summary>
		/// Invokes a projection based on the type of value being represented.
		/// </summary>
		/// <param name="onSuccess">
		/// The projection to invoke if the union is currently representing an instance of <see cref="UnionTypesDemo.Success"/>.
		/// </param>
		/// <param name="onValidationError">
		/// The projection to invoke if the union is currently representing an instance of <see cref="UnionTypesDemo.ValidationError"/>.
		/// </param>
		/// <typeparam name="TMatchResult">
		/// The type of value produced by the projections passed.
		/// </typeparam>
		/// <returns>
		/// The projected value.
		/// </returns>
		public TMatchResult Match<TMatchResult>(
			System.Func<UnionTypesDemo.Success, TMatchResult> onSuccess,
			System.Func<UnionTypesDemo.ValidationError, TMatchResult> onValidationError) =>
		this.__tag switch
		{
			__Tag.Success => onSuccess.Invoke(((UnionTypesDemo.Success)this.__reference!))
			,
			__Tag.ValidationError => onValidationError.Invoke(((UnionTypesDemo.ValidationError)this.__reference!))
			,
			_ => throw new System.InvalidOperationException("Unable to determine the represented type or value. The union type was likely not initialized correctly.")
		}
		;
		#endregion
		
		#region Represented Type
		/// <summary>
		/// Gets the types of value this union type can represent.
		/// </summary>
		public static System.Collections.Generic.IReadOnlyCollection<System.Type> RepresentableTypes { get; } = 
			UnionTypesDemo_ResultSave_ScopedData.RepresentableTypes;
		/// <summary>
		/// Gets the type of value represented by this instance.
		/// </summary>
		public System.Type RepresentedType => 
		this.__tag switch
		{
			__Tag.Success => typeof(UnionTypesDemo.Success),
			__Tag.ValidationError => typeof(UnionTypesDemo.ValidationError),
			_ => throw new System.InvalidOperationException("Unable to determine the represented type or value. The union type was likely not initialized correctly.")
		}
		;
		#endregion
		
		#region Is/As Properties
		
		/// <summary>
		/// Gets a value indicating whether this instance is representing a value of type <see cref="UnionTypesDemo.Success"/>.
		/// </summary>
		public System.Boolean IsSuccess => __tag == __Tag.Success;
		
		/// <summary>
		/// Gets a value indicating whether this instance is representing a value of type <see cref="UnionTypesDemo.ValidationError"/>.
		/// </summary>
		public System.Boolean IsValidationError => __tag == __Tag.ValidationError;
		
		/// <summary>
		/// Retrieves the value represented by this instance as a <see cref="UnionTypesDemo.Success"/>.
		/// </summary>
		public UnionTypesDemo.Success? AsSuccess => __tag == __Tag.Success
		? ((UnionTypesDemo.Success)this.__reference!)
		: null;
		
		/// <summary>
		/// Retrieves the value represented by this instance as a <see cref="UnionTypesDemo.ValidationError"/>.
		/// </summary>
		public UnionTypesDemo.ValidationError? AsValidationError => __tag == __Tag.ValidationError
		? ((UnionTypesDemo.ValidationError)this.__reference!)
		: null;
		#endregion
		
		#region Is Group Properties
		
		#endregion
		
		#region Is/As Functions
		
		/// <summary>
		/// Determines whether this instance is representing a value of type <see cref="UnionTypesDemo.Success"/>.
		/// </summary>
		/// <returns>
		/// <see langword="true"/> if this instance is representing a value of type <see cref="UnionTypesDemo.Success"/>; otherwise, <see langword="false"/>.
		/// </returns>
		/// <param name="value">
		/// If this instance is representing a value of type <see cref="UnionTypesDemo.Success"/>, this parameter will contain that value; otherwise, <see langword="default"/>.
		/// </param>
		public System.Boolean TryAsSuccess([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out UnionTypesDemo.Success value)
		{
			if(this.__tag == __Tag.Success)
			{
				value = ((UnionTypesDemo.Success)this.__reference!);
				return true;
			}
			value = default;
			return false;
		}
		
		/// <summary>
		/// Determines whether this instance is representing a value of type <see cref="UnionTypesDemo.ValidationError"/>.
		/// </summary>
		/// <returns>
		/// <see langword="true"/> if this instance is representing a value of type <see cref="UnionTypesDemo.ValidationError"/>; otherwise, <see langword="false"/>.
		/// </returns>
		/// <param name="value">
		/// If this instance is representing a value of type <see cref="UnionTypesDemo.ValidationError"/>, this parameter will contain that value; otherwise, <see langword="default"/>.
		/// </param>
		public System.Boolean TryAsValidationError([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out UnionTypesDemo.ValidationError value)
		{
			if(this.__tag == __Tag.ValidationError)
			{
				value = ((UnionTypesDemo.ValidationError)this.__reference!);
				return true;
			}
			value = default;
			return false;
		}
		/// <summary>
		/// Determines whether this instance is representing a value of type <typeparamref name="TValue"/>.
		/// </summary>
		/// <typeparam name="TValue">
		/// The type whose representation in this instance to determine.
		/// </typeparam>
		/// <returns>
		/// <see langword="true"/> if this instance is representing a value of type <typeparamref name="TValue"/>; otherwise, <see langword="false"/>.
		/// </returns>
		public System.Boolean Is<TValue>() =>typeof(TValue) ==this.__tag switch
		{
			__Tag.Success => typeof(UnionTypesDemo.Success),
			__Tag.ValidationError => typeof(UnionTypesDemo.ValidationError),
			_ => throw new System.InvalidOperationException("Unable to determine the represented type or value. The union type was likely not initialized correctly.")
		}
		;
		/// <summary>
		/// Determines whether this instance is representing a value of type <typeparamref name="TValue"/>.
		/// </summary>
		/// <param name="value">
		/// If this instance is representing a value of type <typeparamref name="TValue"/>, this parameter will contain that value; otherwise, <see langword="default"/>.
		/// </param>
		/// <typeparam name="TValue">
		/// The type whose representation in this instance to determine.
		/// </typeparam>
		/// <returns>
		/// <see langword="true"/> if this instance is representing a value of type <typeparamref name="TValue"/>; otherwise, <see langword="false"/>.
		/// </returns>
		public System.Boolean Is<TValue>(out TValue? value)
		{
			var metadataName = RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.GetFullString(typeof(TValue));
			switch(metadataName)
			{
				case "UnionTypesDemo.Success":
				{
					value = (RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.UnsafeConvert<UnionTypesDemo.Success, TValue>((UnionTypesDemo.Success)this.__reference!));
					return true;
				}
				
				case "UnionTypesDemo.ValidationError":
				{
					value = (RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.UnsafeConvert<UnionTypesDemo.ValidationError, TValue>((UnionTypesDemo.ValidationError)this.__reference!));
					return true;
				}
				default:
				{
					
					{
						value = default;
						return false;
					}
				}
			}
		}
		/// <summary>
		/// Determines whether this instance is representing an instance of <paramref name="type"/>.
		/// </summary>
		/// <param name="type">
		/// The type whose representation in this instance to determine.
		/// </param>
		/// <returns>
		/// <see langword="true"/> if this instance is representing an instance of <paramref name="type"/>; otherwise, <see langword="false"/>.
		/// </returns>
		public System.Boolean Is(System.Type type) =>
		type == this.__tag switch
		{
			__Tag.Success => typeof(UnionTypesDemo.Success),
			__Tag.ValidationError => typeof(UnionTypesDemo.ValidationError),
			_ => throw new System.InvalidOperationException("Unable to determine the represented type or value. The union type was likely not initialized correctly.")
		}
		;
		/// <summary>
		/// Retrieves the value represented by this instance as an instance of <typeparamref name="TValue"/>.
		/// </summary>
		/// <typeparam name="TValue">
		/// The type to retrieve the represented value as.
		/// </typeparam>
		/// <returns>
		/// The currently represented value as an instance of <typeparamref name="TValue"/>.
		/// </returns>
		public TValue As<TValue>() =>
		this.__tag switch
		{
			__Tag.Success => typeof(TValue) == typeof(UnionTypesDemo.Success)
			? (RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.UnsafeConvert<UnionTypesDemo.Success, TValue>((UnionTypesDemo.Success)this.__reference!))
			: throw new System.InvalidOperationException($"Unable to convert from an instance of {typeof(UnionTypesDemo.ResultSave)} representing a value of type {this.RepresentedType} to an instance of {typeof(TValue)}."),
			__Tag.ValidationError => typeof(TValue) == typeof(UnionTypesDemo.ValidationError)
			? (RhoMicro.CodeAnalysis.UnionsGenerator.Generated.Util.UnsafeConvert<UnionTypesDemo.ValidationError, TValue>((UnionTypesDemo.ValidationError)this.__reference!))
			: throw new System.InvalidOperationException($"Unable to convert from an instance of {typeof(UnionTypesDemo.ResultSave)} representing a value of type {this.RepresentedType} to an instance of {typeof(TValue)}."),
			_ => throw new System.InvalidOperationException("Unable to determine the represented type or value. The union type was likely not initialized correctly.")
		}
		;
		#endregion
		
		#region ToString
		/// <inheritdoc/>
		public override System.String ToString()
		{
			var stringRepresentation = this.__tag switch
			{
				__Tag.Success => ((this.__reference!)?.ToString() ?? System.String.Empty),
				__Tag.ValidationError => ((this.__reference!)?.ToString() ?? System.String.Empty),
				_ => throw new System.InvalidOperationException("Unable to determine the represented type or value. The union type was likely not initialized correctly.")
			}
			;
			var result = $"ResultSave({(__tag == __Tag.Success ? "<Success>" : "Success")}|{(__tag == __Tag.ValidationError ? "<ValidationError>" : "ValidationError")}){{{stringRepresentation}}}";
			return result;
		}
		#endregion
		
		#region GetHashCode
		/// <inheritdoc/>
		public override System.Int32 GetHashCode() => 
		this.__tag switch
		{
			__Tag.Success => (System.Collections.Generic.EqualityComparer<UnionTypesDemo.Success>.Default.GetHashCode(((UnionTypesDemo.Success)this.__reference!))),
			__Tag.ValidationError => (System.Collections.Generic.EqualityComparer<UnionTypesDemo.ValidationError>.Default.GetHashCode(((UnionTypesDemo.ValidationError)this.__reference!))),
			_ => throw new System.InvalidOperationException("Unable to determine the represented type or value. The union type was likely not initialized correctly.")
		}
		;
		#endregion
		
		#region Equality
		/// <inheritdoc/>
		public override System.Boolean Equals(System.Object? obj) =>
			obj is ResultSave union && Equals(union);
		/// <inheritdoc/>
		public System.Boolean Equals(ResultSave? other) =>
			ReferenceEquals(other, this)
			|| other != null
			&& this.__tag == other.__tag
			&& this.__tag switch
			{
				__Tag.Success => (System.Collections.Generic.EqualityComparer<UnionTypesDemo.Success>.Default.Equals(((UnionTypesDemo.Success)this.__reference!), ((UnionTypesDemo.Success)other.__reference!))),
				__Tag.ValidationError => (System.Collections.Generic.EqualityComparer<UnionTypesDemo.ValidationError>.Default.Equals(((UnionTypesDemo.ValidationError)this.__reference!), ((UnionTypesDemo.ValidationError)other.__reference!))),
				_ => throw new System.InvalidOperationException("Unable to determine the represented type or value. The union type was likely not initialized correctly.")
			}
			;
		
		#endregion
		
		#region Conversions
		
		#region Representable Type Conversions
		
		/// <summary>
		/// Converts an instance of the representable type <see cref="UnionTypesDemo.Success"/> to the union type <see cref="UnionTypesDemo.ResultSave"/>.
		/// </summary>
		/// <param name="value">
		/// The value to convert.
		/// </param>
		/// <returns>
		/// The union type instance.
		/// </returns>
		public static implicit operator ResultSave(UnionTypesDemo.Success value) => CreateFromSuccess(value);
		/// <summary>
		/// Converts an instance of the union type <see cref="UnionTypesDemo.ResultSave"/> to the representable type <see cref="UnionTypesDemo.Success"/>.
		/// </summary>
		/// <param name="union">
		/// The union to convert.
		/// </param>
		/// <returns>
		/// The represented value.
		/// </returns>
		public static explicit operator UnionTypesDemo.Success(UnionTypesDemo.ResultSave union) =>union.__tag == __Tag.Success?
		((UnionTypesDemo.Success)union.__reference!):throw new System.InvalidOperationException($"Unable to convert from an instance of {typeof(ResultSave)} representing a value of type {union.RepresentedType} to an instance of {typeof(UnionTypesDemo.Success)}.");
		
		/// <summary>
		/// Converts an instance of the representable type <see cref="UnionTypesDemo.ValidationError"/> to the union type <see cref="UnionTypesDemo.ResultSave"/>.
		/// </summary>
		/// <param name="value">
		/// The value to convert.
		/// </param>
		/// <returns>
		/// The union type instance.
		/// </returns>
		public static implicit operator ResultSave(UnionTypesDemo.ValidationError value) => CreateFromValidationError(value);
		/// <summary>
		/// Converts an instance of the union type <see cref="UnionTypesDemo.ResultSave"/> to the representable type <see cref="UnionTypesDemo.ValidationError"/>.
		/// </summary>
		/// <param name="union">
		/// The union to convert.
		/// </param>
		/// <returns>
		/// The represented value.
		/// </returns>
		public static explicit operator UnionTypesDemo.ValidationError(UnionTypesDemo.ResultSave union) =>union.__tag == __Tag.ValidationError?
		((UnionTypesDemo.ValidationError)union.__reference!):throw new System.InvalidOperationException($"Unable to convert from an instance of {typeof(ResultSave)} representing a value of type {union.RepresentedType} to an instance of {typeof(UnionTypesDemo.ValidationError)}.");
		#endregion
		
		#region Related Type Conversions
		#endregion
		#endregion
	}
}
#endregion

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/UnionsGenerator