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


<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


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());



using UnionGen.Types;
using UnionGen;
namespace UnionTypesDemo;

[Union<Result<int>, NotFound>]
public partial struct ResultSave
{
}





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

// <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