153 lines
4.6 KiB
C#
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];
|
|
}
|
|
} |