using System.Diagnostics.CodeAnalysis; namespace SJK.Functional; public interface IEither { IEither MapLeft(Func mapping); IEither MapRight(Func mapping); TLeft Reduce(Func mapping); (TLeft?, TRight?) Deconstruct(); TResult Match(Func left, Func right); void Match(Action left, Action right); IEither Bind(Func> 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()); // } // public static Result TestEither() // { // return new Result(); // } // } public struct Either { 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.Create(5,union => // { // union.Set(5.0); // var s = union.Match( // i => i.ToString(), // i => i.ToString(), // i => i.ToString() // ); // }); } public (Option left, Option right) Deconstruct() => (_left,_right); [MemberNotNullWhen(true,nameof(_right)),MemberNotNullWhen(false,nameof(_left))] public TLeft Reduce(Func mapping) => IsLeft?_left:mapping(_right); public TResult Match(Func left, Func right) => IsLeft ? left(_left) : right(_right); Either MapLeft(Func mapping) => IsLeft? Either.Left(mapping(_left)) :Either.Right(_right); Either MapRight(Func mapping) => IsLeft? Either.Left(_left) :Either.Right(mapping(_right)); public static Either Left(TLeft left) => new(left,default,true); public static Either Right(TRight right) => new(default,right,false); } public ref struct Union where T : unmanaged where T2 : unmanaged where T3 : unmanaged { private byte _type; private Span _data; public static unsafe int SizeInBytes => System.Math.Max(System.Math.Max(sizeof(T),sizeof(T2)),sizeof(T3)); public Union(Span buffer) { _data = buffer; } public Union() { _data = new byte[SizeInBytes]; } public static void Create(T value,Action> action) { Span span = stackalloc byte[SizeInBytes]; var union = new Union(span); union.Set(value); action(union); } public static void Create(T2 value,Action> action) { Span span = stackalloc byte[SizeInBytes]; var union = new Union(span); union.Set(value); action(union); } public static void Create(T3 value,Action> action) { Span span = stackalloc byte[SizeInBytes]; var union = new Union(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, Action t2, Action t3 ) { switch(_type) { case 1: t(As()); break; case 2: t2(As()); break; case 3: t3(As()); break; }; } public TResult Match( Func t, Func t2, Func t3 ) => _type switch { 1=>t(As()), 2=>t2(As()), 3=>t3(As()), _ => throw new NotSupportedException() }; public ref T As() where T : unmanaged { return ref System.Runtime.InteropServices.MemoryMarshal.Cast(_data)[0]; } }