namespace Just.Railway; internal enum ResultState : byte { Bottom = 0, Error = 0b01, Success = 0b11, } public readonly partial struct Result : IEquatable { [SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Simplified source generation")] internal SuccessUnit Value { [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(); } internal readonly Error? Error; internal readonly ResultState State; internal Result(Error? error) { Error = error; State = error is null ? ResultState.Success : ResultState.Error; } [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] public static Result Success() => new(null); [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] public static Result Success(T value) => new(value); [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] public static Result<(T1, T2)> Success(T1 value1, T2 value2) => new((value1, value2)); [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] public static Result<(T1, T2, T3)> Success(T1 value1, T2 value2, T3 value3) => new((value1, value2, value3)); [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] public static Result<(T1, T2, T3, T4)> Success(T1 value1, T2 value2, T3 value3, T4 value4) => new((value1, value2, value3, value4)); [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] public static Result<(T1, T2, T3, T4, T5)> Success(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5) => new((value1, value2, value3, value4, value5)); [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] public static Result Failure(string error) => Error.New(error ?? throw new ArgumentNullException(nameof(error))); [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] public static Result Failure(Error error) => new(error ?? throw new ArgumentNullException(nameof(error))); [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] public static Result Failure(Exception exception) => new(Error.New(exception) ?? throw new ArgumentNullException(nameof(exception))); [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] public static Result Failure(string error) => Error.New(error ?? throw new ArgumentNullException(nameof(error))); [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] public static Result Failure(Error error) => new(error ?? throw new ArgumentNullException(nameof(error))); [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] public static Result Failure(Exception exception) => new(Error.New(exception) ?? throw new ArgumentNullException(nameof(exception))); [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Result(Error error) => new(error ?? throw new ArgumentNullException(nameof(error))); [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Result(Exception exception) => new( new ExceptionalError(exception ?? throw new ArgumentNullException(nameof(exception)))); [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Result(Result result) => result.State switch { ResultState.Success => new(new SuccessUnit()), ResultState.Error => new(result.Error!), _ => throw new ResultNotInitializedException(nameof(result)) }; [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Result(SuccessUnit _) => new(null); [Pure] public bool IsSuccess => Error is null; [Pure] public bool IsFailure => Error is not null; [Pure] public bool TryGetValue([MaybeNullWhen(false)]out SuccessUnit? u, [MaybeNullWhen(true), NotNullWhen(false)]out Error? error) { switch (State) { case ResultState.Success: u = new SuccessUnit(); error = null; return true; case ResultState.Error: u = default; error = Error!; return false; default: throw new ResultNotInitializedException(); } } [Pure] public bool TryGetError([MaybeNullWhen(false)]out Error error) { if (IsSuccess) { error = default; return false; } if (IsFailure) { error = Error!; return true; } throw new ResultNotInitializedException(); } [Pure] public override string ToString() => State switch { ResultState.Success => "", ResultState.Error => Error!.ToString(), _ => throw new ResultNotInitializedException() }; [Pure] public override int GetHashCode() => State switch { ResultState.Success => 0, ResultState.Error => Error!.GetHashCode(), _ => throw new ResultNotInitializedException() }; [Pure] public override bool Equals(object? obj) => obj is Result other && Equals(other); [Pure] public bool Equals(Result other) { if (State == ResultState.Bottom) throw new ResultNotInitializedException(); return Error == other.Error; } [Pure] public static bool operator ==(Result left, Result right) => left.Equals(right); [Pure] public static bool operator !=(Result left, Result right) => !(left == right); } public readonly struct Result : IEquatable> { internal readonly Error? Error; internal readonly T Value; internal readonly ResultState State; internal Result(Error error) { Error = error ?? throw new ArgumentNullException(nameof(error)); State = ResultState.Error; Value = default!; } internal Result(T value) { Value = value; State = ResultState.Success; Error = default; } [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] public static explicit operator Result(Result result) => result.State switch { ResultState.Success => new(null), ResultState.Error => new(result.Error!), _ => throw new ResultNotInitializedException(nameof(result)) }; [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Result(Error error) => new(error); [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Result(Exception exception) => new( new ExceptionalError(exception ?? throw new ArgumentNullException(nameof(exception)))); [Pure, MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Result(T value) => new(value); [Pure] public bool IsSuccess => State == ResultState.Success; [Pure] public bool IsFailure => State == ResultState.Error; [Pure] public bool TryGetValue([MaybeNullWhen(false)]out T value, [MaybeNullWhen(true), NotNullWhen(false)]out Error? error) { switch (State) { case ResultState.Success: value = Value; error = null; return true; case ResultState.Error: value = default; error = Error!; return false; default: throw new ResultNotInitializedException(); } } [Pure] public bool TryGetValue([MaybeNullWhen(false)]out T value) { switch (State) { case ResultState.Success: value = Value; return true; case ResultState.Error: value = default; return false; default: throw new ResultNotInitializedException(); } } [Pure] public bool TryGetError([MaybeNullWhen(false)]out Error error) { switch (State) { case ResultState.Success: error = default; return false; case ResultState.Error: error = Error!; return true; default: throw new ResultNotInitializedException(); } } [Pure] public Result Cast() { switch (State) { case ResultState.Error: return Error!; case ResultState.Success: { if (Value is R ret) return ret; if (typeof(R).IsAssignableFrom(typeof(T)) && Value is null) return default(R)!; return (R)(object)Value!; } default: throw new ResultNotInitializedException(); } } [Pure] public override string ToString() => State switch { ResultState.Success => Value?.ToString() ?? "", ResultState.Error => Error!.ToString(), _ => throw new ResultNotInitializedException() }; [Pure] public override int GetHashCode() => State switch { ResultState.Success => Value?.GetHashCode() ?? 0, ResultState.Error => Error!.GetHashCode(), _ => throw new ResultNotInitializedException() }; [Pure] public override bool Equals(object? obj) => obj is Result other && Equals(other); [Pure] public bool Equals(Result other) { if (State == ResultState.Bottom) throw new ResultNotInitializedException(); if (IsSuccess != other.IsSuccess) return false; return IsSuccess ? ReflectionHelper.IsEqual(Value, other.Value) : Error == other.Error; } [Pure] public static bool operator ==(Result left, Result right) => left.Equals(right); [Pure] public static bool operator !=(Result left, Result right) => !(left == right); } public readonly struct SuccessUnit : IEquatable { public override bool Equals([NotNullWhen(true)] object? obj) => obj is SuccessUnit; public bool Equals(SuccessUnit other) => true; public override int GetHashCode() => 0; public override string ToString() => "success"; public static bool operator ==(SuccessUnit left, SuccessUnit right) => left.Equals(right); public static bool operator !=(SuccessUnit left, SuccessUnit right) => !(left == right); } [Serializable] public class ResultNotInitializedException : InvalidOperationException { public ResultNotInitializedException(string variableName = "this") : base("Result was not properly initialized.") { VariableName = variableName; } public string VariableName { get; } }