RSCG – UnionGen

name UnionGen
nuget https://www.nuget.org/packages/UnionGen/
link https://github.com/markushaslinger/union_source_generator
author M. Haslinger

Generating unions between types

 

This is how you can use UnionGen .

The code that you start with is

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
<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="UnionGen" Version="1.4.0" />
    </ItemGroup>
 
</Project>

The code that you will use is

1
2
3
4
5
6
7
8
9
using UnionTypesDemo;
 
Console.WriteLine("Save or not");
var data = SaveToDatabase.Save(0);
Console.WriteLine(data.IsNotFound);
data = SaveToDatabase.Save(1);
Console.WriteLine(data.IsResultOfInt32);
 
Console.WriteLine(data.AsResultOfInt32());
1
2
3
4
5
6
7
8
using UnionGen.Types;
using UnionGen;
namespace UnionTypesDemo;
 
[Union<Result<int>, NotFound>]
public partial struct ResultSave
{
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
using UnionGen.Types;
 
namespace UnionTypesDemo;
 
public class SaveToDatabase
{
    public static ResultSave Save(int i)
    {
        if(i ==0)
        {
            return new NotFound();
        }
        return new Result<int>(i);
    }
}

 

The code that is generated is

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// <auto-generated by UnionSourceGen />
#nullable enable
using System;
namespace UnionTypesDemo
{
 
    public readonly partial struct ResultSave : IEquatable<ResultSave>
    {
        private readonly UnionGen.Types.Result<int> _value0;
        private readonly UnionGen.Types.NotFound _value1;
        private readonly UnionGen.InternalUtil.StateByte _state;
 
        private ResultSave(int index, int actualTypeIndex)
        {
            _state = new UnionGen.InternalUtil.StateByte(index, actualTypeIndex);
        }
 
        public ResultSave(UnionGen.Types.Result<int> value): this(0, 0)
        {
            _value0 = value;
        }
 
        public ResultSave(UnionGen.Types.NotFound value): this(1, 1)
        {
            _value1 = value;
        }
 
        [Obsolete(UnionGen.InternalUtil.UnionGenInternalConst.DefaultConstructorWarning, true)]
        public ResultSave(): this(0, 0) {}
 
        public bool IsResultOfInt32 => _state.Index == 0;
        public bool IsNotFound => _state.Index == 1;
 
        public UnionGen.Types.Result<int> AsResultOfInt32() =>
            IsResultOfInt32
                ? _value0
                : throw UnionGen.InternalUtil.ExceptionHelper.ThrowNotOfType(GetTypeName(0), GetTypeName(_state.ActualTypeIndex));
         
        public UnionGen.Types.NotFound AsNotFound() =>
            IsNotFound
                ? _value1
                : throw UnionGen.InternalUtil.ExceptionHelper.ThrowNotOfType(GetTypeName(1), GetTypeName(_state.ActualTypeIndex));
 
        public static implicit operator ResultSave(UnionGen.Types.Result<int> value) => new ResultSave(value);
        public static implicit operator ResultSave(UnionGen.Types.NotFound value) => new ResultSave(value);
        public static bool operator ==(ResultSave left, ResultSave right) => left.Equals(right);
        public static bool operator !=(ResultSave left, ResultSave right) => !left.Equals(right);
 
        public TResult Match<TResult>(Func<UnionGen.Types.Result<int>, TResult> withResultOfInt32, Func<UnionGen.Types.NotFound, TResult> withNotFound) =>      
            _state.ActualTypeIndex switch
            {
                0 => withResultOfInt32(_value0),
                1 => withNotFound(_value1),
                _ => throw UnionGen.InternalUtil.ExceptionHelper.ThrowUnknownTypeIndex(_state.ActualTypeIndex)
            };
 
        public void Switch(Action<UnionGen.Types.Result<int>> forResultOfInt32, Action<UnionGen.Types.NotFound> forNotFound)     
        {
            switch (_state.ActualTypeIndex)
            {
                case 0: forResultOfInt32(_value0); break;
                case 1: forNotFound(_value1); break;
                default: throw UnionGen.InternalUtil.ExceptionHelper.ThrowUnknownTypeIndex(_state.ActualTypeIndex);
            }
        }
 
        public override string ToString() =>        
            _state.Index switch
            {
                0 => _value0.ToString()!,
                1 => _value1.ToString()!,
                _ => throw UnionGen.InternalUtil.ExceptionHelper.ThrowUnknownTypeIndex(_state.Index)
            };
 
        public bool Equals(ResultSave other) =>
            _state.Index == other._state.Index
                && _state.Index switch
                {
                    0 => _value0.Equals(other._value0),
                    1 => _value1.Equals(other._value1),
                    _ => false
                };
 
        public override bool Equals(object? obj)
        {
            if (ReferenceEquals(null, obj))
            {
                return false;
            }
            return obj is ResultSave other && Equals(other);
        }
 
        public override int GetHashCode(){     
            unchecked
            {
                var hash = _state.Index switch
                {
                    0 => _value0.GetHashCode(),
                    1 => _value1.GetHashCode(),
                    _ => 0
                };
                return (hash * 397) ^ _state.Index;
            }
        }
 
        public string GetTypeName(int index) =>
            index switch
            {
                0 => "UnionGen.Types.Result<int>",
                1 => "UnionGen.Types.NotFound",
                _ => throw UnionGen.InternalUtil.ExceptionHelper.ThrowUnknownTypeIndex(index)
            };
 
    }
 
}

Code and pdf at

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