diff --git a/JustDotNet.Railway.sln b/JustDotNet.Railway.sln index f22dfd8..e2d2807 100644 --- a/JustDotNet.Railway.sln +++ b/JustDotNet.Railway.sln @@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Railway", "Railway\Railway. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Raliway.Tests", "Raliway.Tests\Raliway.Tests.csproj", "{607F91E4-83A2-48C4-BAC2-2205BEE81D93}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Railway.SourceGenerator", "Railway.SourceGenerator\Railway.SourceGenerator.csproj", "{1A3B8F0A-7A30-4AA8-BC15-47FA2D75B6BF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -24,5 +26,9 @@ Global {607F91E4-83A2-48C4-BAC2-2205BEE81D93}.Debug|Any CPU.Build.0 = Debug|Any CPU {607F91E4-83A2-48C4-BAC2-2205BEE81D93}.Release|Any CPU.ActiveCfg = Release|Any CPU {607F91E4-83A2-48C4-BAC2-2205BEE81D93}.Release|Any CPU.Build.0 = Release|Any CPU + {1A3B8F0A-7A30-4AA8-BC15-47FA2D75B6BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1A3B8F0A-7A30-4AA8-BC15-47FA2D75B6BF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1A3B8F0A-7A30-4AA8-BC15-47FA2D75B6BF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1A3B8F0A-7A30-4AA8-BC15-47FA2D75B6BF}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/Railway.SourceGenerator/Constants.cs b/Railway.SourceGenerator/Constants.cs new file mode 100644 index 0000000..04f6512 --- /dev/null +++ b/Railway.SourceGenerator/Constants.cs @@ -0,0 +1,7 @@ +namespace Just.Railway.SourceGen; + +internal static class Constants +{ + public const int MaxResultTupleSize = 4; + +} diff --git a/Railway.SourceGenerator/Railway.SourceGenerator.csproj b/Railway.SourceGenerator/Railway.SourceGenerator.csproj new file mode 100644 index 0000000..bfb2f7a --- /dev/null +++ b/Railway.SourceGenerator/Railway.SourceGenerator.csproj @@ -0,0 +1,20 @@ + + + + netstandard2.0 + latest + false + Just.Railway.SourceGen + + true + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + diff --git a/Railway.SourceGenerator/ResultCombineGenerator.cs b/Railway.SourceGenerator/ResultCombineGenerator.cs new file mode 100644 index 0000000..5bf911e --- /dev/null +++ b/Railway.SourceGenerator/ResultCombineGenerator.cs @@ -0,0 +1,214 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using Microsoft.CodeAnalysis; + +namespace Just.Railway.SourceGen; + +[Generator] +public class ResultCombineGenerator : IIncrementalGenerator +{ + public ResultCombineGenerator() + { + } + + public void Initialize(IncrementalGeneratorInitializationContext context) + { + context.RegisterSourceOutput(context.CompilationProvider, Execute); + } + + private void Execute(SourceProductionContext context, Compilation source) + { + var methods = GenerateCombineMethods(); + var code = $$""" + #nullable enable + using System; + using System.Collections.Generic; + using System.Diagnostics.Contracts; + using System.CodeDom.Compiler; + + namespace Just.Railway; + + public readonly partial struct Result + { + {{methods}} + } + """; + + context.AddSource("Result.Combine.g.cs", code); + } + + private string GenerateCombineMethods() + { + var sb = new StringBuilder(); + + for (int i = 2; i <= Constants.MaxResultTupleSize; i++) + { + GenerateCombineMethodsForArgCount(sb, argCount: i); + } + + return sb.ToString(); + } + + private void GenerateCombineMethodsForArgCount(StringBuilder sb, int argCount) + { + sb.AppendLine($"#region Combine {argCount} Results"); + + GenerateGetBottomMethod(sb, argCount); + + var argsResultTupleSizes = new List>(); + Span templateCounts = stackalloc int[argCount]; + + Permute(templateCounts, argsResultTupleSizes); + + foreach (var argResultTupleSizes in argsResultTupleSizes) + { + sb.AppendLine(GenerateCombineMethodBody(argResultTupleSizes)); + } + + sb.AppendLine("#endregion"); + + static void Permute(Span templateCounts, ICollection> argsResultTupleSizes, int lvl = 0) + { + int sum = 0; + for (int i = 0; i < lvl; i++) + { + sum += templateCounts[i]; + } + for (templateCounts[lvl] = 0; templateCounts[lvl] <= Constants.MaxResultTupleSize - sum; templateCounts[lvl]++) + { + if (lvl == templateCounts.Length - 1) + { + argsResultTupleSizes.Add(templateCounts.ToImmutableArray()); + continue; + } + Permute(templateCounts, argsResultTupleSizes, lvl + 1); + } + } + } + + private static void GenerateGetBottomMethod(StringBuilder sb, int argCount) + { + var args = Enumerable.Range(1, argCount) + .Select(i => $"result{i}") + .ToImmutableArray(); + var argsDecl = string.Join(", ", args.Select(x => $"ResultState {x}")); + sb.AppendLine($"[GeneratedCodeAttribute(\"{nameof(ResultCombineGenerator)}\", \"1.0.0.0\")]"); + sb.AppendLine($"private static IEnumerable GetBottom({argsDecl})"); + sb.AppendLine("{"); + foreach (var arg in args) + { + sb.AppendLine($" if ({arg} == ResultState.Bottom) yield return \"{arg}\";"); + } + sb.AppendLine("}"); + } + + private string GenerateCombineMethodBody(ImmutableArray argResultTupleSizes) + { + var resultTupleSize = argResultTupleSizes.Sum(); + + var paramNames = Enumerable.Range(1, argResultTupleSizes.Length) + .Select(i => $"result{i}") + .ToImmutableArray(); + var templateArgNames = Enumerable.Range(1, resultTupleSize) + .Select(i => $"T{i}") + .ToImmutableArray(); + + string templateDecl = templateArgNames.IsEmpty + ? string.Empty + : $"<{string.Join(", ", templateArgNames)}>"; + string resultTypeDecl = GetResultTypeDecl(templateArgNames); + string paramDecl; + { + var paramDeclBuilder = new StringBuilder(); + int currentTemplateArg = 0; + for (int i = 0; i < argResultTupleSizes.Length; i++) + { + var argResultTupleSize = argResultTupleSizes[i]; + string currentParamType = GetResultTypeDecl(templateArgNames.Slice(currentTemplateArg, argResultTupleSize)); + currentTemplateArg += argResultTupleSize; + paramDeclBuilder.Append($"in {currentParamType} {paramNames[i]}, "); + } + paramDeclBuilder.Remove(paramDeclBuilder.Length-2, 2); + paramDecl = paramDeclBuilder.ToString(); + } + + var paramNameStates = paramNames.Select(x => $"{x}.State") + .ToImmutableArray(); + string bottomStateCheck = string.Join(" & ", paramNameStates); + string statesSeparatedList = string.Join(", ", paramNameStates); + + string failureChecks; + { + var failureChecksBuilder = new StringBuilder(); + foreach (var paramName in paramNames) + { + failureChecksBuilder.AppendLine($" if ({paramName}.IsFailure) error += {paramName}.Error;"); + } + failureChecks = failureChecksBuilder.ToString(); + } + string resultExpansion; + switch (resultTupleSize) + { + case 0: + resultExpansion = "null"; + break; + + case 1: + resultExpansion = $"{paramNames[argResultTupleSizes.IndexOf(1)]}.Value"; + break; + + default: + var resultExpansionBuilder = new StringBuilder(); + resultExpansionBuilder.Append("("); + for (int i = 0; i < argResultTupleSizes.Length; i++) + { + if (argResultTupleSizes[i] == 0) continue; + if (argResultTupleSizes[i] == 1) + { + resultExpansionBuilder.Append($"{paramNames[i]}.Value, "); + continue; + } + + for (int valueIndex = 1; valueIndex <= argResultTupleSizes[i]; valueIndex++) + { + resultExpansionBuilder.Append($"{paramNames[i]}.Value.Item{valueIndex}, "); + } + } + resultExpansionBuilder.Remove(resultExpansionBuilder.Length - 2, 2); + resultExpansionBuilder.Append(")"); + resultExpansion = resultExpansionBuilder.ToString(); + break; + } + + string returnExpr = $"return error is null ? new({resultExpansion}) : new(error);"; + var method = $$""" + [GeneratedCodeAttribute("{{nameof(ResultCombineGenerator)}}", "1.0.0.0")] + [PureAttribute] + public static {{resultTypeDecl}} Combine{{templateDecl}}({{paramDecl}}) + { + if (({{bottomStateCheck}}) == ResultState.Bottom) + { + throw new ResultNotInitializedException(string.Join(';', GetBottom({{statesSeparatedList}}))); + } + Error? error = null; + {{failureChecks}} + {{returnExpr}} + } + """; + return method; + + static string GetResultTypeDecl(IReadOnlyList templateArgNames) + { + return templateArgNames.Count switch + { + 0 => "Result", + 1 => $"Result<{templateArgNames[0]}>", + _ => $"Result<({string.Join(", ", templateArgNames)})>" + }; + } + } +} + diff --git a/Railway/Railway.csproj b/Railway/Railway.csproj index f2164b9..6bc385f 100644 --- a/Railway/Railway.csproj +++ b/Railway/Railway.csproj @@ -4,6 +4,7 @@ net8.0 enable enable + true Just.Railway Just.Railway @@ -18,5 +19,11 @@ + + + + diff --git a/Railway/Result.cs b/Railway/Result.cs index 0d0f664..83c94f0 100644 --- a/Railway/Result.cs +++ b/Railway/Result.cs @@ -6,7 +6,7 @@ internal enum ResultState : byte Bottom = 0, Error = 0b01, Success = 0b11, } -public readonly struct Result : IEquatable +public readonly partial struct Result : IEquatable { internal readonly Error? Error; internal readonly ResultState State; @@ -22,1061 +22,6 @@ public readonly struct Result : IEquatable [Pure] public static Result Failure(Error error) => new(error ?? throw new ArgumentNullException(nameof(error))); [Pure] public static Result Failure(Error error) => new(error ?? throw new ArgumentNullException(nameof(error))); -#region Combine 2 Results - [Pure] public static Result Combine(in Result result1, in Result result2) - { - Error? error = null; - - if ((result1.State & result2.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - return new(error); - } - [Pure] public static Result<(T1, T2)> Combine(in Result result1, in Result result2) - { - Error? error = null; - - if ((result1.State & result2.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - return error is null - ? new((result1.Value, result2.Value)) - : new(error); - } - [Pure] public static Result Combine(in Result result1, in Result result2) - { - Error? error = null; - - if ((result1.State & result2.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - return error is null - ? new(result1.Value) - : new(error); - } - [Pure] public static Result Combine(in Result result1, in Result result2) - { - Error? error = null; - - if ((result1.State & result2.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - return error is null - ? new(result2.Value) - : new(error); - } -#endregion - -#region Combine 3 Results - [Pure] public static Result Combine(in Result result1, in Result result2, in Result result3) - { - Error? error = null; - - if ((result1.State & result2.State & result3.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State, result3.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2, ResultState r3) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - if (r3 == ResultState.Bottom) - yield return nameof(result3); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - if (result3.IsFailure) - { - error += result3.Error; - } - return new(error); - } - [Pure] public static Result<(T1, T2, T3)> Combine(in Result result1, in Result result2, in Result result3) - { - Error? error = null; - - if ((result1.State & result2.State & result3.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State, result3.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2, ResultState r3) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - if (r3 == ResultState.Bottom) - yield return nameof(result3); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - if (result3.IsFailure) - { - error += result3.Error; - } - return error is null - ? new((result1.Value, result2.Value, result3.Value)) - : new(error); - } - [Pure] public static Result<(T1, T2)> Combine(in Result result1, in Result result2, in Result result3) - { - Error? error = null; - - if ((result1.State & result2.State & result3.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State, result3.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2, ResultState r3) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - if (r3 == ResultState.Bottom) - yield return nameof(result3); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - if (result3.IsFailure) - { - error += result3.Error; - } - return error is null - ? new((result1.Value, result2.Value)) - : new(error); - } - [Pure] public static Result<(T1, T2)> Combine(in Result result1, in Result result2, in Result result3) - { - Error? error = null; - - if ((result1.State & result2.State & result3.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State, result3.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2, ResultState r3) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - if (r3 == ResultState.Bottom) - yield return nameof(result3); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - if (result3.IsFailure) - { - error += result3.Error; - } - return error is null - ? new((result2.Value, result3.Value)) - : new(error); - } - [Pure] public static Result<(T1, T2)> Combine(in Result result1, in Result result2, in Result result3) - { - Error? error = null; - - if ((result1.State & result2.State & result3.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State, result3.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2, ResultState r3) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - if (r3 == ResultState.Bottom) - yield return nameof(result3); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - if (result3.IsFailure) - { - error += result3.Error; - } - return error is null - ? new((result1.Value, result3.Value)) - : new(error); - } - [Pure] public static Result Combine(in Result result1, in Result result2, in Result result3) - { - Error? error = null; - - if ((result1.State & result2.State & result3.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State, result3.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2, ResultState r3) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - if (r3 == ResultState.Bottom) - yield return nameof(result3); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - if (result3.IsFailure) - { - error += result3.Error; - } - return error is null - ? new(result1.Value) - : new(error); - } - [Pure] public static Result Combine(in Result result1, in Result result2, in Result result3) - { - Error? error = null; - - if ((result1.State & result2.State & result3.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State, result3.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2, ResultState r3) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - if (r3 == ResultState.Bottom) - yield return nameof(result3); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - if (result3.IsFailure) - { - error += result3.Error; - } - return error is null - ? new(result2.Value) - : new(error); - } - [Pure] public static Result Combine(in Result result1, in Result result2, in Result result3) - { - Error? error = null; - - if ((result1.State & result2.State & result3.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State, result3.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2, ResultState r3) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - if (r3 == ResultState.Bottom) - yield return nameof(result3); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - if (result3.IsFailure) - { - error += result3.Error; - } - return error is null - ? new(result3.Value) - : new(error); - } -#endregion - -#region Combine 4 Results - [Pure] public static Result Combine(in Result result1, in Result result2, in Result result3, in Result result4) - { - Error? error = null; - - if ((result1.State & result2.State & result3.State & result4.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State, result3.State, result4.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2, ResultState r3, ResultState r4) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - if (r3 == ResultState.Bottom) - yield return nameof(result3); - if (r4 == ResultState.Bottom) - yield return nameof(result4); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - if (result3.IsFailure) - { - error += result3.Error; - } - if (result4.IsFailure) - { - error += result4.Error; - } - return new(error); - } - [Pure] public static Result<(T1, T2, T3, T4)> Combine(in Result result1, in Result result2, in Result result3, in Result result4) - { - Error? error = null; - - if ((result1.State & result2.State & result3.State & result4.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State, result3.State, result4.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2, ResultState r3, ResultState r4) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - if (r3 == ResultState.Bottom) - yield return nameof(result3); - if (r4 == ResultState.Bottom) - yield return nameof(result4); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - if (result3.IsFailure) - { - error += result3.Error; - } - if (result4.IsFailure) - { - error += result4.Error; - } - return error is null - ? new((result1.Value, result2.Value, result3.Value, result4.Value)) - : new(error); - } - [Pure] public static Result<(T1, T2, T3)> Combine(in Result result1, in Result result2, in Result result3, in Result result4) - { - Error? error = null; - - if ((result1.State & result2.State & result3.State & result4.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State, result3.State, result4.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2, ResultState r3, ResultState r4) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - if (r3 == ResultState.Bottom) - yield return nameof(result3); - if (r4 == ResultState.Bottom) - yield return nameof(result4); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - if (result3.IsFailure) - { - error += result3.Error; - } - if (result4.IsFailure) - { - error += result4.Error; - } - return error is null - ? new((result2.Value, result3.Value, result4.Value)) - : new(error); - } - [Pure] public static Result<(T1, T2, T3)> Combine(in Result result1, in Result result2, in Result result3, in Result result4) - { - Error? error = null; - - if ((result1.State & result2.State & result3.State & result4.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State, result3.State, result4.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2, ResultState r3, ResultState r4) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - if (r3 == ResultState.Bottom) - yield return nameof(result3); - if (r4 == ResultState.Bottom) - yield return nameof(result4); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - if (result3.IsFailure) - { - error += result3.Error; - } - if (result4.IsFailure) - { - error += result4.Error; - } - return error is null - ? new((result1.Value, result3.Value, result4.Value)) - : new(error); - } - [Pure] public static Result<(T1, T2, T3)> Combine(in Result result1, in Result result2, in Result result3, in Result result4) - { - Error? error = null; - - if ((result1.State & result2.State & result3.State & result4.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State, result3.State, result4.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2, ResultState r3, ResultState r4) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - if (r3 == ResultState.Bottom) - yield return nameof(result3); - if (r4 == ResultState.Bottom) - yield return nameof(result4); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - if (result3.IsFailure) - { - error += result3.Error; - } - if (result4.IsFailure) - { - error += result4.Error; - } - return error is null - ? new((result1.Value, result2.Value, result4.Value)) - : new(error); - } - [Pure] public static Result<(T1, T2, T3)> Combine(in Result result1, in Result result2, in Result result3, in Result result4) - { - Error? error = null; - - if ((result1.State & result2.State & result3.State & result4.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State, result3.State, result4.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2, ResultState r3, ResultState r4) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - if (r3 == ResultState.Bottom) - yield return nameof(result3); - if (r4 == ResultState.Bottom) - yield return nameof(result4); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - if (result3.IsFailure) - { - error += result3.Error; - } - if (result4.IsFailure) - { - error += result4.Error; - } - return error is null - ? new((result1.Value, result2.Value, result3.Value)) - : new(error); - } - [Pure] public static Result<(T1, T2)> Combine(in Result result1, in Result result2, in Result result3, in Result result4) - { - Error? error = null; - - if ((result1.State & result2.State & result3.State & result4.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State, result3.State, result4.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2, ResultState r3, ResultState r4) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - if (r3 == ResultState.Bottom) - yield return nameof(result3); - if (r4 == ResultState.Bottom) - yield return nameof(result4); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - if (result3.IsFailure) - { - error += result3.Error; - } - if (result4.IsFailure) - { - error += result4.Error; - } - return error is null - ? new((result3.Value, result4.Value)) - : new(error); - } - [Pure] public static Result<(T1, T2)> Combine(in Result result1, in Result result2, in Result result3, in Result result4) - { - Error? error = null; - - if ((result1.State & result2.State & result3.State & result4.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State, result3.State, result4.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2, ResultState r3, ResultState r4) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - if (r3 == ResultState.Bottom) - yield return nameof(result3); - if (r4 == ResultState.Bottom) - yield return nameof(result4); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - if (result3.IsFailure) - { - error += result3.Error; - } - if (result4.IsFailure) - { - error += result4.Error; - } - return error is null - ? new((result2.Value, result4.Value)) - : new(error); - } - [Pure] public static Result<(T1, T2)> Combine(in Result result1, in Result result2, in Result result3, in Result result4) - { - Error? error = null; - - if ((result1.State & result2.State & result3.State & result4.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State, result3.State, result4.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2, ResultState r3, ResultState r4) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - if (r3 == ResultState.Bottom) - yield return nameof(result3); - if (r4 == ResultState.Bottom) - yield return nameof(result4); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - if (result3.IsFailure) - { - error += result3.Error; - } - if (result4.IsFailure) - { - error += result4.Error; - } - return error is null - ? new((result2.Value, result3.Value)) - : new(error); - } - [Pure] public static Result<(T1, T2)> Combine(in Result result1, in Result result2, in Result result3, in Result result4) - { - Error? error = null; - - if ((result1.State & result2.State & result3.State & result4.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State, result3.State, result4.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2, ResultState r3, ResultState r4) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - if (r3 == ResultState.Bottom) - yield return nameof(result3); - if (r4 == ResultState.Bottom) - yield return nameof(result4); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - if (result3.IsFailure) - { - error += result3.Error; - } - if (result4.IsFailure) - { - error += result4.Error; - } - return error is null - ? new((result1.Value, result4.Value)) - : new(error); - } - [Pure] public static Result<(T1, T2)> Combine(in Result result1, in Result result2, in Result result3, in Result result4) - { - Error? error = null; - - if ((result1.State & result2.State & result3.State & result4.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State, result3.State, result4.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2, ResultState r3, ResultState r4) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - if (r3 == ResultState.Bottom) - yield return nameof(result3); - if (r4 == ResultState.Bottom) - yield return nameof(result4); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - if (result3.IsFailure) - { - error += result3.Error; - } - if (result4.IsFailure) - { - error += result4.Error; - } - return error is null - ? new((result1.Value, result3.Value)) - : new(error); - } - [Pure] public static Result<(T1, T2)> Combine(in Result result1, in Result result2, in Result result3, in Result result4) - { - Error? error = null; - - if ((result1.State & result2.State & result3.State & result4.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State, result3.State, result4.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2, ResultState r3, ResultState r4) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - if (r3 == ResultState.Bottom) - yield return nameof(result3); - if (r4 == ResultState.Bottom) - yield return nameof(result4); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - if (result3.IsFailure) - { - error += result3.Error; - } - if (result4.IsFailure) - { - error += result4.Error; - } - return error is null - ? new((result1.Value, result2.Value)) - : new(error); - } - [Pure] public static Result Combine(in Result result1, in Result result2, in Result result3, in Result result4) - { - Error? error = null; - - if ((result1.State & result2.State & result3.State & result4.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State, result3.State, result4.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2, ResultState r3, ResultState r4) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - if (r3 == ResultState.Bottom) - yield return nameof(result3); - if (r4 == ResultState.Bottom) - yield return nameof(result4); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - if (result3.IsFailure) - { - error += result3.Error; - } - if (result4.IsFailure) - { - error += result4.Error; - } - return error is null - ? new(result4.Value) - : new(error); - } - [Pure] public static Result Combine(in Result result1, in Result result2, in Result result3, in Result result4) - { - Error? error = null; - - if ((result1.State & result2.State & result3.State & result4.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State, result3.State, result4.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2, ResultState r3, ResultState r4) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - if (r3 == ResultState.Bottom) - yield return nameof(result3); - if (r4 == ResultState.Bottom) - yield return nameof(result4); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - if (result3.IsFailure) - { - error += result3.Error; - } - if (result4.IsFailure) - { - error += result4.Error; - } - return error is null - ? new(result3.Value) - : new(error); - } - [Pure] public static Result Combine(in Result result1, in Result result2, in Result result3, in Result result4) - { - Error? error = null; - - if ((result1.State & result2.State & result3.State & result4.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State, result3.State, result4.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2, ResultState r3, ResultState r4) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - if (r3 == ResultState.Bottom) - yield return nameof(result3); - if (r4 == ResultState.Bottom) - yield return nameof(result4); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - if (result3.IsFailure) - { - error += result3.Error; - } - if (result4.IsFailure) - { - error += result4.Error; - } - return error is null - ? new(result2.Value) - : new(error); - } - [Pure] public static Result Combine(in Result result1, in Result result2, in Result result3, in Result result4) - { - Error? error = null; - - if ((result1.State & result2.State & result3.State & result4.State) == ResultState.Bottom) - { - throw new ResultNotInitializedException(string.Join(';', GetBottom(result1.State, result2.State, result3.State, result4.State))); - - static IEnumerable GetBottom(ResultState r1, ResultState r2, ResultState r3, ResultState r4) - { - if (r1 == ResultState.Bottom) - yield return nameof(result1); - if (r2 == ResultState.Bottom) - yield return nameof(result2); - if (r3 == ResultState.Bottom) - yield return nameof(result3); - if (r4 == ResultState.Bottom) - yield return nameof(result4); - } - } - - if (result1.IsFailure) - { - error += result1.Error; - } - if (result2.IsFailure) - { - error += result2.Error; - } - if (result3.IsFailure) - { - error += result3.Error; - } - if (result4.IsFailure) - { - error += result4.Error; - } - return error is null - ? new(result1.Value) - : new(error); - } -#endregion - [Pure] public static implicit operator Result(Error error) => new(error ?? throw new ArgumentNullException(nameof(error))); [Pure] public static implicit operator Result(Result result) => result.State switch { diff --git a/Raliway.Tests/Results/GeneralUsage.cs b/Raliway.Tests/Results/GeneralUsage.cs index 14e1593..ecbab17 100644 --- a/Raliway.Tests/Results/GeneralUsage.cs +++ b/Raliway.Tests/Results/GeneralUsage.cs @@ -135,7 +135,7 @@ public class GeneralUsage return "satisfied"; } ); - + // Then Assert.Equal("satisfied", result); }