Skip to content

coplt/Coplt.Union

Repository files navigation

Coplt.Union

.NET MIT

  • Sera.Union
    Nuget openupm
  • Sera.Union.Utilities
    Nuget

Generate Tagged Union using source generator

  • All unmanaged types will overlap
  • All classes will overlap
  • Other types are sequential

Example

[Union]
public readonly partial struct Union1
{
    [UnionTemplate]
    private interface Template
    {
        int A();
        string B();
        bool C();
        (int a, int b) D();
        void E();
        List<int>? F();
        (int a, string b) G();
    }
}

Will generate (pseudocode):

public readonly partial struct Union1
{
    private readonly __impl_ _impl;
    
    // If the first item is a Tag only, it starts at 0, otherwise it starts at 1
    // Use [UnionTag(value)] to explicitly mark enum values
    public enum Tags : byte { A = 1, B, C, D, E, F, G }
    
    private struct __impl_
    {
        public __class_ _class_;            // All classes will overlap
        public __unmanaged_ _unmanaged_;    // All unmanaged types will overlap
        public (int a, string b) _0;        // Mixed types cannot overlap
        public readonly Tags _tag;
        
        [StructLayout(LayoutKind.Explicit)] internal struct __class_
        {
            [FieldOffset(0)] public string _0;
            [FieldOffset(0)] public List<int>? _1;
        }
        [StructLayout(LayoutKind.Explicit)] internal struct __unmanaged_
        {
            [FieldOffset(0)] public int  _0;
            [FieldOffset(0)] public bool _1;
            [FieldOffset(0)] public (int a, int b) _2;
        }
    }
    
    public static Union1 MakeA(int value) { ... }
    public static Union1 MakeB(string value) { ... }
    public static Union1 MakeC(bool value) { ... }
    public static Union1 MakeD((int a, int b) value) { ... }
    public static Union1 MakeE() { ... }
    public static Union1 MakeF(List<int>? value) { ... }
    public static Union1 MakeG((int a, string b) value) { ... }
    
    public readonly Tags Tag { get; }
    public readonly bool IsA { get; }
    public readonly bool IsB { get; }
    public readonly bool IsC { get; }
    public readonly bool IsD { get; }
    public readonly bool IsE { get; }
    public readonly bool IsF { get; }
    public readonly bool IsG { get; }
    
    // ref readonly if sturct is readonly, otherwise ref only
    // If the current tag does not match, a null reference will be returned
    public ref readonly int IsA { get; }
    public ref readonly string IsB { get; }
    public ref readonly bool IsC { get; }
    public ref readonly (int a, int b) IsD { get; }
    // E is a Tag only so there is no value getter
    public ref readonly List<int>? IsF { get; }
    public ref readonly (int a, string b) IsG { get; }
    
    ... Eq Cmp ToString
}

Complete generate output:

Union1.union.g.cs
// <auto-generated/>

#nullable disable warnings
#nullable enable annotations

using Coplt.Union;

public readonly partial struct Union1
    : global::Coplt.Union.ITaggedUnion
    , global::System.IEquatable<Union1>
    , global::System.IComparable<Union1>
#if NET7_0_OR_GREATER
    , global::System.Numerics.IEqualityOperators<Union1, Union1, bool>
    , global::System.Numerics.IComparisonOperators<Union1, Union1, bool>
#endif
{
    private readonly __impl_ _impl;
    private Union1(__impl_ _impl) { this._impl = _impl; }

    public readonly Tags Tag
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => this._impl._tag;
    }

    public enum Tags : byte
    {
        A = 1,
        B,
        C,
        D,
        E,
        F,
        G,
    }

    [global::System.Runtime.CompilerServices.CompilerGenerated]
    private struct __impl_
    {
        public __class_ _class_;
        public __unmanaged_ _unmanaged_;
        public (int a, string b) _0;
        public readonly Tags _tag;

        [global::System.Runtime.CompilerServices.CompilerGenerated]
        [global::System.Runtime.InteropServices.StructLayout(global::System.Runtime.InteropServices.LayoutKind.Explicit)]
        internal struct __class_
        {
            [global::System.Runtime.InteropServices.FieldOffset(0)]
            public string _0;
            [global::System.Runtime.InteropServices.FieldOffset(0)]
            public List<int>? _1;
        }

        [global::System.Runtime.CompilerServices.CompilerGenerated]
        [global::System.Runtime.InteropServices.StructLayout(global::System.Runtime.InteropServices.LayoutKind.Explicit)]
        internal struct __unmanaged_
        {
            [global::System.Runtime.InteropServices.FieldOffset(0)]
            public int _0;
            [global::System.Runtime.InteropServices.FieldOffset(0)]
            public bool _1;
            [global::System.Runtime.InteropServices.FieldOffset(0)]
            public (int a, int b) _2;
        }

        public __impl_(Tags _tag)
        {
            this._class_ = default;
            global::System.Runtime.CompilerServices.Unsafe.SkipInit(out this._unmanaged_);
            this._0 = default!;
            this._tag = _tag;
        }
    }

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static Union1 MakeA(int value)
    {
        var _impl = new __impl_(Tags.A);
        _impl._unmanaged_._0 = value;
        return new Union1(_impl);
    }
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static Union1 MakeB(string value)
    {
        var _impl = new __impl_(Tags.B);
        _impl._class_._0 = value;
        return new Union1(_impl);
    }
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static Union1 MakeC(bool value)
    {
        var _impl = new __impl_(Tags.C);
        _impl._unmanaged_._1 = value;
        return new Union1(_impl);
    }
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static Union1 MakeD((int a, int b) value)
    {
        var _impl = new __impl_(Tags.D);
        _impl._unmanaged_._2 = value;
        return new Union1(_impl);
    }
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static Union1 MakeE()
    {
        var _impl = new __impl_(Tags.E);
        return new Union1(_impl);
    }
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static Union1 MakeF(List<int>? value)
    {
        var _impl = new __impl_(Tags.F);
        _impl._class_._1 = value;
        return new Union1(_impl);
    }
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static Union1 MakeG((int a, string b) value)
    {
        var _impl = new __impl_(Tags.G);
        _impl._0 = value;
        return new Union1(_impl);
    }

    public readonly bool IsA
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => this._impl._tag == Tags.A;
    }
    public readonly bool IsB
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => this._impl._tag == Tags.B;
    }
    public readonly bool IsC
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => this._impl._tag == Tags.C;
    }
    public readonly bool IsD
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => this._impl._tag == Tags.D;
    }
    public readonly bool IsE
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => this._impl._tag == Tags.E;
    }
    public readonly bool IsF
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => this._impl._tag == Tags.F;
    }
    public readonly bool IsG
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => this._impl._tag == Tags.G;
    }

    [global::System.Diagnostics.CodeAnalysis.UnscopedRef]
    public ref readonly int A
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => ref !this.IsA ? ref global::System.Runtime.CompilerServices.Unsafe.NullRef<int>() : ref this._impl._unmanaged_._0!;
    }
    [global::System.Diagnostics.CodeAnalysis.UnscopedRef]
    public ref readonly string B
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => ref !this.IsB ? ref global::System.Runtime.CompilerServices.Unsafe.NullRef<string>() : ref this._impl._class_._0!;
    }
    [global::System.Diagnostics.CodeAnalysis.UnscopedRef]
    public ref readonly bool C
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => ref !this.IsC ? ref global::System.Runtime.CompilerServices.Unsafe.NullRef<bool>() : ref this._impl._unmanaged_._1!;
    }
    [global::System.Diagnostics.CodeAnalysis.UnscopedRef]
    public ref readonly (int a, int b) D
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => ref !this.IsD ? ref global::System.Runtime.CompilerServices.Unsafe.NullRef<(int a, int b)>() : ref this._impl._unmanaged_._2!;
    }
    [global::System.Diagnostics.CodeAnalysis.UnscopedRef]
    public ref readonly List<int>? F
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => ref !this.IsF ? ref global::System.Runtime.CompilerServices.Unsafe.NullRef<List<int>?>() : ref this._impl._class_._1!;
    }
    [global::System.Diagnostics.CodeAnalysis.UnscopedRef]
    public ref readonly (int a, string b) G
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => ref !this.IsG ? ref global::System.Runtime.CompilerServices.Unsafe.NullRef<(int a, string b)>() : ref this._impl._0!;
    }

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly bool Equals(Union1 other) => this.Tag != other.Tag ? false : this.Tag switch
    {
        Tags.A => global::System.Collections.Generic.EqualityComparer<int>.Default.Equals(this.A, other.A),
        Tags.B => global::System.Collections.Generic.EqualityComparer<string>.Default.Equals(this.B, other.B),
        Tags.C => global::System.Collections.Generic.EqualityComparer<bool>.Default.Equals(this.C, other.C),
        Tags.D => global::System.Collections.Generic.EqualityComparer<(int a, int b)>.Default.Equals(this.D, other.D),
        Tags.F => global::System.Collections.Generic.EqualityComparer<List<int>?>.Default.Equals(this.F, other.F),
        Tags.G => global::System.Collections.Generic.EqualityComparer<(int a, string b)>.Default.Equals(this.G, other.G),
        _ => true,
    };

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly override int GetHashCode() => this.Tag switch
    {
        Tags.A => global::System.HashCode.Combine(this.Tag, this.A),
        Tags.B => global::System.HashCode.Combine(this.Tag, this.B),
        Tags.C => global::System.HashCode.Combine(this.Tag, this.C),
        Tags.D => global::System.HashCode.Combine(this.Tag, this.D),
        Tags.F => global::System.HashCode.Combine(this.Tag, this.F),
        Tags.G => global::System.HashCode.Combine(this.Tag, this.G),
        _ => global::System.HashCode.Combine(this.Tag),
    };

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly override bool Equals(object? obj) => obj is Union1 other && Equals(other);

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator ==(Union1 left, Union1 right) => Equals(left, right);
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator !=(Union1 left, Union1 right) => !Equals(left, right);

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly int CompareTo(Union1 other) => this.Tag != other.Tag ? global::System.Collections.Generic.Comparer<Tags>.Default.Compare(this.Tag, other.Tag) : this.Tag switch
    {
        Tags.A => global::System.Collections.Generic.Comparer<int>.Default.Compare(this.A, other.A),
        Tags.B => global::System.Collections.Generic.Comparer<string>.Default.Compare(this.B, other.B),
        Tags.C => global::System.Collections.Generic.Comparer<bool>.Default.Compare(this.C, other.C),
        Tags.D => global::System.Collections.Generic.Comparer<(int a, int b)>.Default.Compare(this.D, other.D),
        Tags.F => global::System.Collections.Generic.Comparer<List<int>?>.Default.Compare(this.F, other.F),
        Tags.G => global::System.Collections.Generic.Comparer<(int a, string b)>.Default.Compare(this.G, other.G),
        _ => 0,
    };

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator <(Union1 left, Union1 right) => left.CompareTo(right) < 0;
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator >(Union1 left, Union1 right) => left.CompareTo(right) > 0;
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator <=(Union1 left, Union1 right) => left.CompareTo(right) <= 0;
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator >=(Union1 left, Union1 right) => left.CompareTo(right) >= 0;

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly override string ToString() => this.Tag switch
    {
        Tags.A => $"{nameof(Union1)}.{nameof(Tags.A)} {{ {(this.A)} }}",
        Tags.B => $"{nameof(Union1)}.{nameof(Tags.B)} {{ {(this.B)} }}",
        Tags.C => $"{nameof(Union1)}.{nameof(Tags.C)} {{ {(this.C)} }}",
        Tags.D => $"{nameof(Union1)}.{nameof(Tags.D)} {{ {(this.D)} }}",
        Tags.E => $"{nameof(Union1)}.{nameof(Tags.E)}",
        Tags.F => $"{nameof(Union1)}.{nameof(Tags.F)} {{ {(this.F)} }}",
        Tags.G => $"{nameof(Union1)}.{nameof(Tags.G)} {{ {(this.G)} }}",
        _ => nameof(Union1),
    };
}

How to use

You can manually determine the Tag or use pattern matching.
But remember C# does not have enum exhaustion semantics.

var u = Union1.MakeA(123);

if (u is { Tag: Union1.Tags.A, A: var a }) { }

if (u is { IsA: true, A: var a }) { }

if (u.IsA)
{
    var a = u.A;
}

switch (u.Tag)
{
    case Union1.Tags.A:
        break;
  ...
}

switch (u.Tag)
{
    case { IsA: true, A: var a }:
        break;
  ...
}

Support generics

Generics will not overlap

[Union]
public partial struct Option<T>
{
    [UnionTemplate]
    private interface Template
    {
        T Some();
        void None();
    }
}

[Union]
public partial struct Result<T, E>
{
    [UnionTemplate]
    private interface Template
    {
        T Ok();
        E Err();
    }
}

Generate output:

Option[T].union.g.cs
// <auto-generated/>

#nullable disable warnings
#nullable enable annotations

using Coplt.Union;

public partial struct Option<T>
    : global::Coplt.Union.ITaggedUnion
    , global::System.IEquatable<Option<T>>
    , global::System.IComparable<Option<T>>
#if NET7_0_OR_GREATER
    , global::System.Numerics.IEqualityOperators<Option<T>, Option<T>, bool>
    , global::System.Numerics.IComparisonOperators<Option<T>, Option<T>, bool>
#endif
{
    private __impl_ _impl;
    private Option(__impl_ _impl) { this._impl = _impl; }

    public readonly Tags Tag
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => this._impl._tag;
    }

    public enum Tags : byte
    {
        Some = 1,
        None,
    }

    [global::System.Runtime.CompilerServices.CompilerGenerated]
    private struct __impl_
    {
        public T _0;
        public readonly Tags _tag;

        public __impl_(Tags _tag)
        {
            this._0 = default!;
            this._tag = _tag;
        }
    }

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static Option<T> MakeSome(T value)
    {
        var _impl = new __impl_(Tags.Some);
        _impl._0 = value;
        return new Option<T>(_impl);
    }
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static Option<T> MakeNone()
    {
        var _impl = new __impl_(Tags.None);
        return new Option<T>(_impl);
    }

    public readonly bool IsSome
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => this._impl._tag == Tags.Some;
    }
    public readonly bool IsNone
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => this._impl._tag == Tags.None;
    }

    [global::System.Diagnostics.CodeAnalysis.UnscopedRef]
    public ref T Some
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => ref !this.IsSome ? ref global::System.Runtime.CompilerServices.Unsafe.NullRef<T>() : ref this._impl._0!;
    }

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly bool Equals(Option<T> other) => this.Tag != other.Tag ? false : this.Tag switch
    {
        Tags.Some => global::System.Collections.Generic.EqualityComparer<T>.Default.Equals(global::System.Runtime.CompilerServices.Unsafe.AsRef<Option<T>>(in this).Some, other.Some),
        _ => true,
    };

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly override int GetHashCode() => this.Tag switch
    {
        Tags.Some => global::System.HashCode.Combine(this.Tag, global::System.Runtime.CompilerServices.Unsafe.AsRef<Option<T>>(in this).Some),
        _ => global::System.HashCode.Combine(this.Tag),
    };

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly override bool Equals(object? obj) => obj is Option<T> other && Equals(other);

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator ==(Option<T> left, Option<T> right) => Equals(left, right);
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator !=(Option<T> left, Option<T> right) => !Equals(left, right);

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly int CompareTo(Option<T> other) => this.Tag != other.Tag ? global::System.Collections.Generic.Comparer<Tags>.Default.Compare(this.Tag, other.Tag) : this.Tag switch
    {
        Tags.Some => global::System.Collections.Generic.Comparer<T>.Default.Compare(global::System.Runtime.CompilerServices.Unsafe.AsRef<Option<T>>(in this).Some, other.Some),
        _ => 0,
    };

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator <(Option<T> left, Option<T> right) => left.CompareTo(right) < 0;
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator >(Option<T> left, Option<T> right) => left.CompareTo(right) > 0;
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator <=(Option<T> left, Option<T> right) => left.CompareTo(right) <= 0;
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator >=(Option<T> left, Option<T> right) => left.CompareTo(right) >= 0;

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly override string ToString() => this.Tag switch
    {
        Tags.Some => $"{nameof(Option<T>)}.{nameof(Tags.Some)} {{ {(global::System.Runtime.CompilerServices.Unsafe.AsRef<Option<T>>(in this).Some)} }}",
        Tags.None => $"{nameof(Option<T>)}.{nameof(Tags.None)}",
        _ => nameof(Option<T>),
    };
}

Result[T,E].union.g.cs
// <auto-generated/>

#nullable disable warnings
#nullable enable annotations

using Coplt.Union;

public partial struct Result<T, E>
    : global::Coplt.Union.ITaggedUnion
    , global::System.IEquatable<Result<T, E>>
    , global::System.IComparable<Result<T, E>>
#if NET7_0_OR_GREATER
    , global::System.Numerics.IEqualityOperators<Result<T, E>, Result<T, E>, bool>
    , global::System.Numerics.IComparisonOperators<Result<T, E>, Result<T, E>, bool>
#endif
{
    private __impl_ _impl;
    private Result(__impl_ _impl) { this._impl = _impl; }

    public readonly Tags Tag
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => this._impl._tag;
    }

    public enum Tags : byte
    {
        Ok = 1,
        Err,
    }

    [global::System.Runtime.CompilerServices.CompilerGenerated]
    private struct __impl_
    {
        public T _0;
        public E _1;
        public readonly Tags _tag;

        public __impl_(Tags _tag)
        {
            this._0 = default!;
            this._1 = default!;
            this._tag = _tag;
        }
    }

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static Result<T, E> MakeOk(T value)
    {
        var _impl = new __impl_(Tags.Ok);
        _impl._0 = value;
        return new Result<T, E>(_impl);
    }
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static Result<T, E> MakeErr(E value)
    {
        var _impl = new __impl_(Tags.Err);
        _impl._1 = value;
        return new Result<T, E>(_impl);
    }

    public readonly bool IsOk
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => this._impl._tag == Tags.Ok;
    }
    public readonly bool IsErr
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => this._impl._tag == Tags.Err;
    }

    [global::System.Diagnostics.CodeAnalysis.UnscopedRef]
    public ref T Ok
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => ref !this.IsOk ? ref global::System.Runtime.CompilerServices.Unsafe.NullRef<T>() : ref this._impl._0!;
    }
    [global::System.Diagnostics.CodeAnalysis.UnscopedRef]
    public ref E Err
    {
        [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
        get => ref !this.IsErr ? ref global::System.Runtime.CompilerServices.Unsafe.NullRef<E>() : ref this._impl._1!;
    }

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly bool Equals(Result<T, E> other) => this.Tag != other.Tag ? false : this.Tag switch
    {
        Tags.Ok => global::System.Collections.Generic.EqualityComparer<T>.Default.Equals(global::System.Runtime.CompilerServices.Unsafe.AsRef<Result<T, E>>(in this).Ok, other.Ok),
        Tags.Err => global::System.Collections.Generic.EqualityComparer<E>.Default.Equals(global::System.Runtime.CompilerServices.Unsafe.AsRef<Result<T, E>>(in this).Err, other.Err),
        _ => true,
    };

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly override int GetHashCode() => this.Tag switch
    {
        Tags.Ok => global::System.HashCode.Combine(this.Tag, global::System.Runtime.CompilerServices.Unsafe.AsRef<Result<T, E>>(in this).Ok),
        Tags.Err => global::System.HashCode.Combine(this.Tag, global::System.Runtime.CompilerServices.Unsafe.AsRef<Result<T, E>>(in this).Err),
        _ => global::System.HashCode.Combine(this.Tag),
    };

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly override bool Equals(object? obj) => obj is Result<T, E> other && Equals(other);

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator ==(Result<T, E> left, Result<T, E> right) => Equals(left, right);
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator !=(Result<T, E> left, Result<T, E> right) => !Equals(left, right);

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly int CompareTo(Result<T, E> other) => this.Tag != other.Tag ? global::System.Collections.Generic.Comparer<Tags>.Default.Compare(this.Tag, other.Tag) : this.Tag switch
    {
        Tags.Ok => global::System.Collections.Generic.Comparer<T>.Default.Compare(global::System.Runtime.CompilerServices.Unsafe.AsRef<Result<T, E>>(in this).Ok, other.Ok),
        Tags.Err => global::System.Collections.Generic.Comparer<E>.Default.Compare(global::System.Runtime.CompilerServices.Unsafe.AsRef<Result<T, E>>(in this).Err, other.Err),
        _ => 0,
    };

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator <(Result<T, E> left, Result<T, E> right) => left.CompareTo(right) < 0;
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator >(Result<T, E> left, Result<T, E> right) => left.CompareTo(right) > 0;
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator <=(Result<T, E> left, Result<T, E> right) => left.CompareTo(right) <= 0;
    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public static bool operator >=(Result<T, E> left, Result<T, E> right) => left.CompareTo(right) >= 0;

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public readonly override string ToString() => this.Tag switch
    {
        Tags.Ok => $"{nameof(Result<T, E>)}.{nameof(Tags.Ok)} {{ {(global::System.Runtime.CompilerServices.Unsafe.AsRef<Result<T, E>>(in this).Ok)} }}",
        Tags.Err => $"{nameof(Result<T, E>)}.{nameof(Tags.Err)} {{ {(global::System.Runtime.CompilerServices.Unsafe.AsRef<Result<T, E>>(in this).Err)} }}",
        _ => nameof(Result<T, E>),
    };
}