Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add extension methods for combining multiple results into one #18

Merged
merged 9 commits into from
Jul 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ jobs:
with:
dotnet-version: 8.x

- name: Setup .NET 9.0
uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.x
dotnet-quality: preview

- name: Restore dependencies
run: dotnet restore

Expand Down
66 changes: 66 additions & 0 deletions ComparisonBenchmarks/Benchmarks.A_LightResults.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using BenchmarkDotNet.Attributes;
using LightResults;
using LightResults.Extensions.Operations;

namespace ComparisonBenchmarks;

public partial class Benchmarks
{
private IEnumerable<Result> _lightResultsEnumerable = null!;
private IEnumerable<Result<int>> _lightResultsTValueEnumerable = null!;
private IReadOnlyList<Result> _lightResultsReadOnlyList = null!;
private IReadOnlyList<Result<int>> _lightResultsTValueReadOnlyList = null!;

private void SetupLightResults()
{
var random = new Random(Seed);

var enumerable = new List<Result>();
for (int i = 0; i < Iterations; i++)
enumerable.Add(random.Next(0, 1) == 0 ? Result.Ok() : Result.Fail(i.ToString()));
_lightResultsEnumerable = enumerable.AsEnumerable();

var readOnlyList = new List<Result>();
for (int i = 0; i < Iterations; i++)
readOnlyList.Add(random.Next(0, 1) == 0 ? Result.Ok() : Result.Fail(i.ToString()));
_lightResultsReadOnlyList = readOnlyList;

var enumerableT = new List<Result<int>>();
for (int i = 0; i < Iterations; i++)
enumerableT.Add(random.Next(0, 1) == 0 ? Result.Ok(i) : Result.Fail<int>(i.ToString()));
_lightResultsTValueEnumerable = enumerableT.AsEnumerable();

var readOnlyListT = new List<Result<int>>();
for (int i = 0; i < Iterations; i++)
readOnlyListT.Add(random.Next(0, 1) == 0 ? Result.Ok(i) : Result.Fail<int>(i.ToString()));
_lightResultsTValueReadOnlyList = readOnlyListT;
}

[Benchmark(Baseline = true)]
[BenchmarkCategory("A01: Merging multiple results")]
public Result A_LightResults_ResultEnumerable_Collect()
{
return _lightResultsEnumerable.Collect();
}

[Benchmark]
[BenchmarkCategory("A01: Merging multiple results")]
public Result A_LightResults_ResultReadOnlyList_Collect()
{
return _lightResultsReadOnlyList.Collect();
}

[Benchmark(Baseline = true)]
[BenchmarkCategory("A02: Merging multiple results with values")]
public Result<IReadOnlyList<int>> A_LightResults_ResultTValueEnumerable_Collect()
{
return _lightResultsTValueEnumerable.Collect();
}

[Benchmark]
[BenchmarkCategory("A02: Merging multiple results with values")]
public Result<IReadOnlyList<int>> A_LightResults_ResultTValueReadOnlyList_Collect()
{
return _lightResultsTValueReadOnlyList.Collect();
}
}
65 changes: 65 additions & 0 deletions ComparisonBenchmarks/Benchmarks.B_FluentResults.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using BenchmarkDotNet.Attributes;
using FluentResults;

namespace ComparisonBenchmarks;

public partial class Benchmarks
{
private IEnumerable<FluentResults.Result> _fluentResultsEnumerable = null!;
private IEnumerable<FluentResults.Result<int>> _fluentResultsTValueEnumerable = null!;
private IReadOnlyList<FluentResults.Result> _fluentResultsReadOnlyList = null!;
private IReadOnlyList<FluentResults.Result<int>> _fluentResultsTValueReadOnlyList = null!;

private void SetupFluentResults()
{
var random = new Random(Seed);

var enumerable = new List<FluentResults.Result>();
for (var i = 0; i < Iterations; i++)
enumerable.Add(random.Next(0, 1) == 0 ? FluentResults.Result.Ok() : FluentResults.Result.Fail(i.ToString()));
_fluentResultsEnumerable = enumerable.AsEnumerable();

var readOnlyList = new List<FluentResults.Result>();
for (var i = 0; i < Iterations; i++)
readOnlyList.Add(random.Next(0, 1) == 0 ? FluentResults.Result.Ok() : FluentResults.Result.Fail(i.ToString()));
_fluentResultsReadOnlyList = readOnlyList;

var enumerableT = new List<FluentResults.Result<int>>();
for (var i = 0; i < Iterations; i++)
enumerableT.Add(random.Next(0, 1) == 0 ? FluentResults.Result.Ok(i) : FluentResults.Result.Fail<int>(i.ToString()));
_fluentResultsTValueEnumerable = enumerableT.AsEnumerable();

var readOnlyListT = new List<FluentResults.Result<int>>();
for (var i = 0; i < Iterations; i++)
readOnlyListT.Add(random.Next(0, 1) == 0 ? FluentResults.Result.Ok(i) : FluentResults.Result.Fail<int>(i.ToString()));
_fluentResultsTValueReadOnlyList = readOnlyListT;
}

[Benchmark]
[BenchmarkCategory("A01: Merging multiple results")]
public FluentResults.Result B_FluentResults_ResultEnumerable_Merge()
{
return _fluentResultsEnumerable.Merge();
}

[Benchmark]
[BenchmarkCategory("A01: Merging multiple results")]
public FluentResults.Result B_FluentResults_ResultReadOnlyList_Merge()
{
return _fluentResultsReadOnlyList.Merge();
}

[Benchmark]
[BenchmarkCategory("A02: Merging multiple results with values")]
public FluentResults.Result<IEnumerable<int>> B_FluentResults_ResultTValue_Merge()
{
return _fluentResultsTValueEnumerable.Merge();
}

[Benchmark]
[BenchmarkCategory("A02: Merging multiple results with values")]
public FluentResults.Result<IEnumerable<int>> B_FluentResults_ResultTValueReadOnlyList_Merge()
{
return _fluentResultsTValueReadOnlyList.Merge();
}
}
39 changes: 39 additions & 0 deletions ComparisonBenchmarks/Benchmarks.E_Rascal.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using BenchmarkDotNet.Attributes;
using Rascal;

namespace ComparisonBenchmarks;

public partial class Benchmarks
{
private IEnumerable<Rascal.Result<int>> _rascalResultsTValueEnumerable = null!;
private IReadOnlyList<Rascal.Result<int>> _rascalResultsTValueReadOnlyList = null!;

private void SetupRascal()
{
var random = new Random(Seed);

var enumerableT = new List<Rascal.Result<int>>();
for (var i = 0; i < Iterations; i++)
enumerableT.Add(random.Next(0, 1) == 0 ? Prelude.Ok(i) : Prelude.Err<int>(i.ToString()));
_rascalResultsTValueEnumerable = enumerableT.AsEnumerable();

var readOnlyListT = new List<Rascal.Result<int>>();
for (var i = 0; i < Iterations; i++)
readOnlyListT.Add(random.Next(0, 1) == 0 ? Prelude.Ok(i) : Prelude.Err<int>(i.ToString()));
_rascalResultsTValueReadOnlyList = readOnlyListT;
}

[Benchmark]
[BenchmarkCategory("A02: Merging multiple results with values")]
public Rascal.Result<IReadOnlyList<int>> E_Rascal_ResultEnumerable_Sequence()
{
return _rascalResultsTValueEnumerable.Sequence();
}

[Benchmark]
[BenchmarkCategory("A02: Merging multiple results with values")]
public Rascal.Result<IReadOnlyList<int>> E_Rascal_ResultReadOnlyList_Sequence()
{
return _rascalResultsTValueReadOnlyList.Sequence();
}
}
30 changes: 30 additions & 0 deletions ComparisonBenchmarks/Benchmarks.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Jobs;
using JetBrains.Annotations;

namespace ComparisonBenchmarks;

[MemoryDiagnoser]
[SimpleJob(RuntimeMoniker.Net80)]
[IterationTime(250)]
[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
[CategoriesColumn]
[HideColumns(Column.Job, Column.Error, Column.StdDev, Column.Median, Column.RatioSD, Column.Gen0, Column.Gen1, Column.Gen2)]
public partial class Benchmarks
{
[UsedImplicitly]
[Params(10, 100, 1000, 10000)]
public int Iterations { get; set; }

private const int Seed = 42;

[GlobalSetup]
public void GlobalSetup()
{
SetupLightResults();
SetupFluentResults();
SetupRascal();
}
}
24 changes: 24 additions & 0 deletions ComparisonBenchmarks/ComparisonBenchmarks.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>false</IsTestProject>
<Optimize>true</Optimize>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.12" />
<PackageReference Include="FluentResults" Version="3.16.0" />
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0"/>
<PackageReference Include="Rascal" Version="1.1.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\src\LightResults.Extensions.Operations\LightResults.Extensions.Operations.csproj" />
</ItemGroup>

</Project>
5 changes: 5 additions & 0 deletions ComparisonBenchmarks/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Running;
using Benchmarks = ComparisonBenchmarks.Benchmarks;

BenchmarkRunner.Run<Benchmarks>(ManualConfig.Create(DefaultConfig.Instance).WithOptions(ConfigOptions.DisableOptimizationsValidator));
30 changes: 30 additions & 0 deletions LightResults.Extensions.sln
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightResults.Extensions.Ent
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightResults.Extensions.Json", "src\LightResults.Extensions.Json\LightResults.Extensions.Json.csproj", "{7628B10B-1D07-43BA-AC64-1DDF02A2A20F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightResults.Extensions.Operations", "src\LightResults.Extensions.Operations\LightResults.Extensions.Operations.csproj", "{43188181-0188-4653-81C2-57597075BCFA}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{D10E009A-B3B8-4FB3-8B01-F21C383CD513}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ComparisonBenchmarks", "ComparisonBenchmarks\ComparisonBenchmarks.csproj", "{B46CE763-0606-4497-89B7-8FB653D5031D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "tools\Benchmarks\Benchmarks.csproj", "{6DC31D8F-B71A-4A08-A892-5593F54EB82C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightResults.Extensions.Operations.Tests", "tests\LightResults.Extensions.Operations.Tests\LightResults.Extensions.Operations.Tests.csproj", "{D4E8F259-596E-412D-A757-769383865764}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -32,8 +42,28 @@ Global
{7628B10B-1D07-43BA-AC64-1DDF02A2A20F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7628B10B-1D07-43BA-AC64-1DDF02A2A20F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7628B10B-1D07-43BA-AC64-1DDF02A2A20F}.Release|Any CPU.Build.0 = Release|Any CPU
{43188181-0188-4653-81C2-57597075BCFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{43188181-0188-4653-81C2-57597075BCFA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{43188181-0188-4653-81C2-57597075BCFA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{43188181-0188-4653-81C2-57597075BCFA}.Release|Any CPU.Build.0 = Release|Any CPU
{B46CE763-0606-4497-89B7-8FB653D5031D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B46CE763-0606-4497-89B7-8FB653D5031D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B46CE763-0606-4497-89B7-8FB653D5031D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B46CE763-0606-4497-89B7-8FB653D5031D}.Release|Any CPU.Build.0 = Release|Any CPU
{6DC31D8F-B71A-4A08-A892-5593F54EB82C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6DC31D8F-B71A-4A08-A892-5593F54EB82C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6DC31D8F-B71A-4A08-A892-5593F54EB82C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6DC31D8F-B71A-4A08-A892-5593F54EB82C}.Release|Any CPU.Build.0 = Release|Any CPU
{D4E8F259-596E-412D-A757-769383865764}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D4E8F259-596E-412D-A757-769383865764}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D4E8F259-596E-412D-A757-769383865764}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D4E8F259-596E-412D-A757-769383865764}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{93C8BC67-7F34-4935-A671-F0B12AEDB072} = {A6C9FED0-42B6-488C-8961-DE13F291434B}
{B46CE763-0606-4497-89B7-8FB653D5031D} = {D10E009A-B3B8-4FB3-8B01-F21C383CD513}
{93C8BC67-7F34-4935-A671-F0B12AEDB072} = {A6C9FED0-42B6-488C-8961-DE13F291434B}
{6DC31D8F-B71A-4A08-A892-5593F54EB82C} = {D10E009A-B3B8-4FB3-8B01-F21C383CD513}
{D4E8F259-596E-412D-A757-769383865764} = {A6C9FED0-42B6-488C-8961-DE13F291434B}
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@

<!-- Output -->
<PropertyGroup>
<AssemblyName>LightResults.Extensions.Json</AssemblyName>
<Version>8.0.0</Version>
<AssemblyVersion>8.0.0.0</AssemblyVersion>
<FileVersion>8.0.0.0</FileVersion>
<NeutralLanguage>en-US</NeutralLanguage>
<Optimize>true</Optimize>
<IsAotCompatible Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net7.0'))">true</IsAotCompatible>
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
</PropertyGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
using System.Text.Json;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace LightResults.Extensions.Json;

/// <summary>JsonConverterFactory for converting Result types to and from JSON.</summary>
#if NET7_0_OR_GREATER
[RequiresDynamicCode("The native code for this instantiation might not be available at runtime.")]
[RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can\'t validate that the requirements of those annotations are met.")]
#endif
public class ResultJsonConverterFactory : JsonConverterFactory
{
/// <inheritdoc/>
Expand Down
Loading