RSCG – Dusharp
Generate tagged union
This is how you can use Dusharp .
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="Dusharp" Version="0.4.0">
<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);
data.Match(
ok => Console.WriteLine(ok),
()=> Console.WriteLine("Not found")
);
data = SaveToDatabase.Save(1);
data.Match(
ok => Console.WriteLine(ok),
() => Console.WriteLine("Not found")
);
using Dusharp;
namespace UnionTypesDemo;
[Union]
public partial class ResultSave
{
[UnionCase]
public static partial ResultSave Ok(int i);
[UnionCase]
public static partial ResultSave NotFound();
}
namespace UnionTypesDemo;
public class SaveToDatabase
{
public static ResultSave Save(int i)
{
if (i == 0)
{
return ResultSave.NotFound();
}
return ResultSave.Ok(i); ;
}
}
The code that is generated is
// <auto-generated> This file has been auto generated. </auto-generated>
#nullable enable
using System;
using System.Runtime.CompilerServices;
namespace Dusharp
{
public static class ExceptionUtils
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ThrowIfNull<T>(this T value, string paramName)
where T : class
{
if (value == null)
{
ThrowArgumentNull(paramName);
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowUnionInInvalidState() =>
throw new InvalidOperationException("Union in invalid state.");
[MethodImpl(MethodImplOptions.NoInlining)]
private static void ThrowArgumentNull(string paramName) => throw new ArgumentNullException(paramName);
}
}
// <auto-generated> This file has been auto generated. </auto-generated>
#nullable enable
using System;
namespace Dusharp
{
[AttributeUsage(AttributeTargets.Class)]
public sealed class UnionAttribute : Attribute
{
}
}
// <auto-generated> This file has been auto generated. </auto-generated>
#nullable enable
using System;
namespace Dusharp
{
[AttributeUsage(AttributeTargets.Method)]
public sealed class UnionCaseAttribute : Attribute
{
}
}
// <auto-generated> This file has been auto generated. </auto-generated>
#nullable enable
namespace UnionTypesDemo
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("", "CA1000", Justification = "For generic unions.")]
abstract partial class ResultSave : System.IEquatable<ResultSave>
{
private ResultSave() {}
public void Match(System.Action<int> okCase, System.Action notFoundCase)
{
Dusharp.ExceptionUtils.ThrowIfNull(okCase, "okCase");
Dusharp.ExceptionUtils.ThrowIfNull(notFoundCase, "notFoundCase");
{
var unionCase = this as OkCase;
if (!object.ReferenceEquals(unionCase, null)) { okCase(unionCase.i); return; }
}
{
var unionCase = this as NotFoundCase;
if (!object.ReferenceEquals(unionCase, null)) { notFoundCase(); return; }
}
Dusharp.ExceptionUtils.ThrowUnionInInvalidState();
}
public TRet Match<TRet>(System.Func<int, TRet> okCase, System.Func<TRet> notFoundCase)
{
Dusharp.ExceptionUtils.ThrowIfNull(okCase, "okCase");
Dusharp.ExceptionUtils.ThrowIfNull(notFoundCase, "notFoundCase");
{
var unionCase = this as OkCase;
if (!object.ReferenceEquals(unionCase, null)) { return okCase(unionCase.i); }
}
{
var unionCase = this as NotFoundCase;
if (!object.ReferenceEquals(unionCase, null)) { return notFoundCase(); }
}
Dusharp.ExceptionUtils.ThrowUnionInInvalidState();
return default!;
}
public void Match<TState>(TState state, System.Action<TState, int> okCase, System.Action<TState> notFoundCase)
{
Dusharp.ExceptionUtils.ThrowIfNull(okCase, "okCase");
Dusharp.ExceptionUtils.ThrowIfNull(notFoundCase, "notFoundCase");
{
var unionCase = this as OkCase;
if (!object.ReferenceEquals(unionCase, null)) { okCase(state, unionCase.i); return; }
}
{
var unionCase = this as NotFoundCase;
if (!object.ReferenceEquals(unionCase, null)) { notFoundCase(state); return; }
}
Dusharp.ExceptionUtils.ThrowUnionInInvalidState();
}
public TRet Match<TState, TRet>(TState state, System.Func<TState, int, TRet> okCase, System.Func<TState, TRet> notFoundCase)
{
Dusharp.ExceptionUtils.ThrowIfNull(okCase, "okCase");
Dusharp.ExceptionUtils.ThrowIfNull(notFoundCase, "notFoundCase");
{
var unionCase = this as OkCase;
if (!object.ReferenceEquals(unionCase, null)) { return okCase(state, unionCase.i); }
}
{
var unionCase = this as NotFoundCase;
if (!object.ReferenceEquals(unionCase, null)) { return notFoundCase(state); }
}
Dusharp.ExceptionUtils.ThrowUnionInInvalidState();
return default!;
}
public virtual bool Equals(ResultSave? other) { return object.ReferenceEquals(this, other); }
public override bool Equals(object? other) { return object.ReferenceEquals(this, other); }
public override int GetHashCode() { return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); }
public static bool operator ==(ResultSave? left, ResultSave? right)
{
return !object.ReferenceEquals(left, null) ? left.Equals(right) : object.ReferenceEquals(left, right);
}
public static bool operator !=(ResultSave? left, ResultSave? right)
{
return !object.ReferenceEquals(left, null) ? !left.Equals(right) : !object.ReferenceEquals(left, right);
}
private sealed class OkCase : ResultSave
{
public readonly int i;
public OkCase(int i)
{
this.i = i;
}
public override string ToString()
{
return $"Ok {{ i = {i} }}";
}
public override bool Equals(ResultSave? other)
{
if (object.ReferenceEquals(this, other)) return true;
var otherCasted = other as OkCase;
if (object.ReferenceEquals(otherCasted, null)) return false;
return StructuralEquals(otherCasted);
}
public override bool Equals(object? other)
{
if (object.ReferenceEquals(this, other)) return true;
var otherCasted = other as OkCase;
if (object.ReferenceEquals(otherCasted, null)) return false;
return StructuralEquals(otherCasted);
}
public override int GetHashCode()
{
unchecked { return System.Collections.Generic.EqualityComparer<int>.Default.GetHashCode(i!) * -1521134295 + "Ok".GetHashCode(); }
}
private bool StructuralEquals(OkCase other)
{
return System.Collections.Generic.EqualityComparer<int>.Default.Equals(i, other.i);
}
}
public static partial ResultSave Ok(int i)
{
return new OkCase(i);
}
private sealed class NotFoundCase : ResultSave
{
public static readonly NotFoundCase Instance = new NotFoundCase();
public NotFoundCase()
{
}
public override string ToString()
{
return "NotFound";
}
}
public static partial ResultSave NotFound()
{
return NotFoundCase.Instance;
}
}
}
// <auto-generated/>
#nullable enable
using Sera.TaggedUnion;
namespace UnionTypesDemo {
public partial struct ResultSave
: global::Sera.TaggedUnion.ITaggedUnion
, global::System.IEquatable<ResultSave>
, global::System.IComparable<ResultSave>
#if NET7_0_OR_GREATER
, global::System.Numerics.IEqualityOperators<ResultSave, ResultSave, bool>
, global::System.Numerics.IComparisonOperators<ResultSave, ResultSave, bool>
#endif
{
private __impl_ _impl;
private ResultSave(__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,
NotFound = 2,
}
[global::System.Runtime.CompilerServices.CompilerGenerated]
private struct __impl_
{
public __unmanaged_ _unmanaged_;
public readonly Tags _tag;
[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;
}
public __impl_(Tags _tag)
{
global::System.Runtime.CompilerServices.Unsafe.SkipInit(out this._unmanaged_);
this._tag = _tag;
}
}
[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static ResultSave MakeOk(int value)
{
var _impl = new __impl_(Tags.Ok);
_impl._unmanaged_._0 = value;
return new ResultSave(_impl);
}
[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static ResultSave MakeNotFound()
{
var _impl = new __impl_(Tags.NotFound);
return new ResultSave(_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 IsNotFound
{
[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
get => this._impl._tag == Tags.NotFound;
}
public int Ok
{
[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
readonly get => !this.IsOk ? default! : this._impl._unmanaged_._0!;
[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
set { if (this.IsOk) { this._impl._unmanaged_._0 = value; } }
}
[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public readonly bool Equals(ResultSave other) => this.Tag != other.Tag ? false : this.Tag switch
{
Tags.Ok => global::System.Collections.Generic.EqualityComparer<int>.Default.Equals(this.Ok, other.Ok),
_ => 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, this.Ok),
_ => 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 ResultSave other && Equals(other);
[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static bool operator ==(ResultSave left, ResultSave right) => Equals(left, right);
[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static bool operator !=(ResultSave left, ResultSave right) => !Equals(left, right);
[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public readonly int CompareTo(ResultSave 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<int>.Default.Compare(this.Ok, other.Ok),
_ => 0,
};
[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static bool operator <(ResultSave left, ResultSave right) => left.CompareTo(right) < 0;
[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static bool operator >(ResultSave left, ResultSave right) => left.CompareTo(right) > 0;
[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static bool operator <=(ResultSave left, ResultSave right) => left.CompareTo(right) <= 0;
[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static bool operator >=(ResultSave left, ResultSave 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(ResultSave)}.{nameof(Tags.Ok)} {{ {this.Ok} }}",
Tags.NotFound => $"{nameof(ResultSave)}.{nameof(Tags.NotFound)}",
_ => nameof(ResultSave),
};
}
} // namespace UnionTypesDemo
Code and pdf at
https://ignatandrei.github.io/RSCG_Examples/v2/docs/Dusharp