Files
SjkScripts/Functional/IEither.cs
ronnie 262b76c4d5
All checks were successful
Build NuGet / build (push) Successful in 1m43s
Refactored Option<T> to have opertator lifting and removed ref struct for now.
2026-08-07 12:58:11 -04:00

153 lines
4.6 KiB
C#

using System.Diagnostics.CodeAnalysis;
namespace SJK.Functional;
public interface IEither<TLeft, TRight>
{
IEither<TNewLeft, TRight> MapLeft<TNewLeft>(Func<TLeft, TNewLeft> mapping);
IEither<TLeft, TNewRight> MapRight<TNewRight>(Func<TRight, TNewRight> mapping);
TLeft Reduce(Func<TRight, TLeft> mapping);
(TLeft?, TRight?) Deconstruct();
TResult Match<TResult>(Func<TLeft, TResult> left, Func<TRight, TResult> right);
void Match(Action<TLeft> left, Action<TRight> right);
IEither<TLeft, T2> Bind<T2>(Func<TRight, IEither<TLeft, T2>> value);
bool IsRight();
bool IsLeft() => !IsRight();
}
// public class test
// {
// public static void Main()
// {
// var res = TestEither();
// if (res.Ok)
// {
// }
// res.Match(success => Option.Some(success), error => Option.None<int>());
// }
// public static Result<int,bool> TestEither()
// {
// return new Result<int,bool>();
// }
// }
public struct Either<TLeft,TRight>
{
private TLeft? _left;
private TRight? _right;
[MemberNotNullWhen(true,nameof(_left)), MemberNotNullWhen(false,nameof(_right))]
public bool IsLeft {get;init;}
public bool IsRight => !IsLeft;
private Either(TLeft? _left, TRight? right, bool isLeft)
{
this._left = _left;
_right = right;
IsLeft = isLeft;
// Union<int,long,double>.Create(5,union =>
// {
// union.Set(5.0);
// var s = union.Match(
// i => i.ToString(),
// i => i.ToString(),
// i => i.ToString()
// );
// });
}
public (Option<TLeft> left, Option<TRight> right) Deconstruct() => (_left,_right);
[MemberNotNullWhen(true,nameof(_right)),MemberNotNullWhen(false,nameof(_left))]
public TLeft Reduce(Func<TRight,TLeft> mapping) => IsLeft?_left:mapping(_right);
public TResult Match<TResult>(Func<TLeft,TResult> left, Func<TRight,TResult> right) => IsLeft ? left(_left) : right(_right);
Either<TNewLeft, TRight> MapLeft<TNewLeft>(Func<TLeft, TNewLeft> mapping) => IsLeft? Either<TNewLeft,TRight>.Left(mapping(_left)) :Either<TNewLeft,TRight>.Right(_right);
Either<TLeft, TNewRight> MapRight<TNewRight>(Func<TRight, TNewRight> mapping) => IsLeft? Either<TLeft,TNewRight>.Left(_left) :Either<TLeft,TNewRight>.Right(mapping(_right));
public static Either<TLeft,TRight> Left(TLeft left) => new(left,default,true);
public static Either<TLeft,TRight> Right(TRight right) => new(default,right,false);
}
public ref struct Union<T,T2,T3> where T : unmanaged where T2 : unmanaged where T3 : unmanaged
{
private byte _type;
private Span<byte> _data;
public static unsafe int SizeInBytes => System.Math.Max(System.Math.Max(sizeof(T),sizeof(T2)),sizeof(T3));
public Union(Span<byte> buffer)
{
_data = buffer;
}
public Union()
{
_data = new byte[SizeInBytes];
}
public static void Create(T value,Action<Union<T,T2,T3>> action)
{
Span<byte> span = stackalloc byte[SizeInBytes];
var union = new Union<T,T2,T3>(span);
union.Set(value);
action(union);
}
public static void Create(T2 value,Action<Union<T,T2,T3>> action)
{
Span<byte> span = stackalloc byte[SizeInBytes];
var union = new Union<T,T2,T3>(span);
union.Set(value);
action(union);
}
public static void Create(T3 value,Action<Union<T,T2,T3>> action)
{
Span<byte> span = stackalloc byte[SizeInBytes];
var union = new Union<T,T2,T3>(span);
union.Set(value);
action(union);
}
public void Set(in T value)
{
System.Runtime.InteropServices.MemoryMarshal.Write(_data, value);
_type = 1;
}
public void Set(in T2 value)
{
System.Runtime.InteropServices.MemoryMarshal.Write(_data, value);
_type = 2;
}
public void Set(in T3 value)
{
System.Runtime.InteropServices.MemoryMarshal.Write(_data, value);
_type = 3;
}
public void Match(
Action<T> t,
Action<T2> t2,
Action<T3> t3
)
{
switch(_type)
{
case 1:
t(As<T>());
break;
case 2:
t2(As<T2>());
break;
case 3:
t3(As<T3>());
break;
};
}
public TResult Match<TResult>(
Func<T,TResult> t,
Func<T2,TResult> t2,
Func<T3,TResult> t3
) => _type switch
{
1=>t(As<T>()),
2=>t2(As<T2>()),
3=>t3(As<T3>()),
_ => throw new NotSupportedException()
};
public ref T As<T>()
where T : unmanaged
{
return ref System.Runtime.InteropServices.MemoryMarshal.Cast<byte, T>(_data)[0];
}
}