Skip to content
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
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v7
- name: Build
run: make docker-build
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<Nullable>enable</Nullable>
<LangVersion>12.0</LangVersion>
<LangVersion>14.0</LangVersion>
<IsPackable>false</IsPackable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
Expand Down
5 changes: 4 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
FROM mcr.microsoft.com/dotnet/sdk:8.0-alpine
FROM mcr.microsoft.com/dotnet/runtime:8.0-alpine AS net8-runtime
FROM mcr.microsoft.com/dotnet/sdk:10.0-alpine

COPY --from=net8-runtime /usr/share/dotnet/shared/Microsoft.NETCore.App /usr/share/dotnet/shared/Microsoft.NETCore.App

RUN apk add git make

Expand Down
6 changes: 6 additions & 0 deletions global.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"sdk": {
"version": "10.0.302",
"rollForward": "latestFeature"
}
}
2 changes: 1 addition & 1 deletion samples/Eff.Examples.AspNetCore/Domain/IUserService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public interface IUserService
/// </summary>
public class InMemoryUserService : IUserService
{
private ConcurrentDictionary<string, string> _users = new ConcurrentDictionary<string, string>();
private ConcurrentDictionary<string, string> _users = new();

public async Task<bool> Exists(string username) => _users.ContainsKey(username);
public async Task Create(string username, string password)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Nessos.Effects.Examples.AspNetCore.EffBindings;
public class EffectLogger
{
private ConcurrentDictionary<string, ImmutableArray<PersistedEffect>> _store =
new ConcurrentDictionary<string, ImmutableArray<PersistedEffect>>();
new();

/// <summary>
/// Commit an effect trace log, returning a unique identifier that can be used for future retrievals.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace Nessos.Effects.Examples.AspNetCore.EffBindings;
/// </summary>
public class RecordingEffectHandler : DependencyEffectHandler, IDisposableEffectHandler
{
private readonly List<PersistedEffect> _results = new List<PersistedEffect>();
private readonly List<PersistedEffect> _results = [];
private readonly EffectLogger _store;
private readonly HttpResponse _response;

Expand Down
2 changes: 1 addition & 1 deletion samples/Eff.Examples.Config/ConfigEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ public ConfigEffect(string key)

public string Key { get; }

public static ConfigEffect Get(string key) => new ConfigEffect(key);
public static ConfigEffect Get(string key) => new(key);
}
2 changes: 1 addition & 1 deletion samples/Eff.Examples.DependencyInjection/Container.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// Poor man's DI container
public class Container : IContainer, IEnumerable
{
private Dictionary<Type, object> _dict = new Dictionary<Type, object>();
private Dictionary<Type, object> _dict = [];

public void Add<T>(T value) => _dict[typeof(T)] = value!;

Expand Down
4 changes: 2 additions & 2 deletions samples/Eff.Examples.DependencyInjection/DomainLogic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ public static async Eff<bool> CreateNewUser(string userName, string password)

public static async Eff<int> CreateNewUsers((string userName, string password)[] credentials)
{
foreach (var cred in credentials)
foreach (var (userName, password) in credentials)
{
await DomainLogic.CreateNewUser(cred.userName, cred.password);
await DomainLogic.CreateNewUser(userName, password);
}

return credentials.Length;
Expand Down
4 changes: 2 additions & 2 deletions samples/Eff.Examples.DependencyInjection/Program.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Nessos.Effects.DependencyInjection;
using Nessos.Effects.Examples.DependencyInjection;

Container container = new();
Container container = [];
container.Add<ILogger>(new ConsoleLogger());
container.Add<IUserService>(new MockUserService());

Expand All @@ -20,7 +20,7 @@ class ConsoleLogger : ILogger

class MockUserService : IUserService
{
private readonly HashSet<string> _users = new HashSet<string>();
private readonly HashSet<string> _users = [];
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
public async Task<bool> CreateUser(string username, string password) => _users.Add(username);
public async Task<bool> Exists(string username) => _users.Contains(username);
Expand Down
2 changes: 1 addition & 1 deletion samples/Eff.Examples.NonDeterminism/NonDetEffectHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ private static EffectAwaiter<TValue> CloneAwaiter<TValue>(EffectAwaiter<TValue>

public class NonDetResultHolder
{
public List<TResult> Values { get; } = new List<TResult>();
public List<TResult> Values { get; } = [];
public Exception? Exception { get; set; }
public TResult[] GetResults()
{
Expand Down
2 changes: 1 addition & 1 deletion samples/Eff.Examples.RecordReplay/Container.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// Poor man's DI container
public class Container : IContainer, IEnumerable
{
private Dictionary<Type, object> _dict = new Dictionary<Type, object>();
private Dictionary<Type, object> _dict = [];

public void Add<T>(T value) => _dict[typeof(T)] = value!;

Expand Down
2 changes: 1 addition & 1 deletion samples/Eff.Examples.RecordReplay/RecordEffectHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

public class RecordEffectHandler : DependencyEffectHandler
{
private readonly List<RecordedResult> _results = new List<RecordedResult>();
private readonly List<RecordedResult> _results = [];

public RecordEffectHandler(IContainer dependencies) : base(dependencies)
{
Expand Down
2 changes: 1 addition & 1 deletion samples/Eff.Examples.Resumable/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using System.Diagnostics;

// Define a resumable computation
async Eff ResumableWorkflow()
static async Eff ResumableWorkflow()
{
for (int i = 0; i < 20; i++)
{
Expand Down
2 changes: 1 addition & 1 deletion src/Eff/Handlers/EffStateMachine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ internal EffStateMachine()
/// <summary>
/// Gets an identifier for the particular awaiter instance.
/// </summary>
public override string Id => nameof(EffStateMachine<TResult>);
public override string Id => nameof(EffStateMachine<>);

/// <summary>
/// Processes the awaiter using the provided effect handler.
Expand Down
61 changes: 30 additions & 31 deletions tests/Eff.Benchmarks/Benchmark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,49 +4,48 @@
using System.Linq;
using System.Threading.Tasks;

namespace Nessos.Effects.Benchmarks
namespace Nessos.Effects.Benchmarks;

[MemoryDiagnoser]
public class Benchmark
{
[MemoryDiagnoser]
public class Benchmark
{
const int ResultOffset = 50_000; // prevent task caching from kicking in
private readonly int[] _data = Enumerable.Range(0, 100).Select(x => x + ResultOffset).ToArray();
private readonly IEffectHandler _handler = new DefaultEffectHandler();
const int ResultOffset = 50_000; // prevent task caching from kicking in
private readonly int[] _data = Enumerable.Range(0, 100).Select(x => x + ResultOffset).ToArray();
private readonly IEffectHandler _handler = new DefaultEffectHandler();

[Benchmark(Description = "Task Builder", Baseline = true)]
public async ValueTask TaskBuilder() => await TaskFlow.SumOfOddSquares(_data);
[Benchmark(Description = "Task Builder", Baseline = true)]
public async ValueTask TaskBuilder() => await TaskFlow.SumOfOddSquares(_data);

[Benchmark(Description = "Eff Builder")]
public async ValueTask EffBuilder() => await EffFlow.SumOfOddSquares(_data).Run(_handler);
[Benchmark(Description = "Eff Builder")]
public async ValueTask EffBuilder() => await EffFlow.SumOfOddSquares(_data).Run(_handler);

private static class TaskFlow
private static class TaskFlow
{
public static async Task<int> SumOfOddSquares(int[] inputs)
{
public static async Task<int> SumOfOddSquares(int[] inputs)
{
int sum = 0;
foreach (var i in inputs)
if (i % 2 == 1) sum += await Square(i);
int sum = 0;
foreach (var i in inputs)
if (i % 2 == 1) sum += await Square(i);

return sum;
return sum;

static async Task<int> Square(int x) => await Echo(x) * await Echo(x);
static async Task<T> Echo<T>(T x) => x;
}
static async Task<int> Square(int x) => await Echo(x) * await Echo(x);
static async Task<T> Echo<T>(T x) => x;
}
}

private static class EffFlow
private static class EffFlow
{
public static async Eff<int> SumOfOddSquares(int[] inputs)
{
public static async Eff<int> SumOfOddSquares(int[] inputs)
{
int sum = 0;
foreach (var i in inputs)
if (i % 2 == 1) sum += await Square(i);
int sum = 0;
foreach (var i in inputs)
if (i % 2 == 1) sum += await Square(i);

return sum;
return sum;

static async Eff<int> Square(int x) => await Echo(x) * await Echo(x);
static async Eff<T> Echo<T>(T x) => x;
}
static async Eff<int> Square(int x) => await Echo(x) * await Echo(x);
static async Eff<T> Echo<T>(T x) => x;
}
}
}
15 changes: 7 additions & 8 deletions tests/Eff.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
using System;
using BenchmarkDotNet.Running;

namespace Nessos.Effects.Benchmarks
namespace Nessos.Effects.Benchmarks;

class Program
{
class Program
static void Main(string[] args)
{
static void Main(string[] args)
{
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
var switcher = new BenchmarkSwitcher(assembly);
var summaries = switcher.Run(args);
}
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
var switcher = new BenchmarkSwitcher(assembly);
var summaries = switcher.Run(args);
}
}
8 changes: 4 additions & 4 deletions tests/Eff.Tests/CancellationEffectHandlerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class CancellationEffectHandlerTests : EffectHandlerTests
[Fact]
public async Task Stub_CanceledToken_ShouldThrowOperationCanceledException()
{
async Eff<int> Test() => 42;
static async Eff<int> Test() => 42;

var handler = new CancellationEffectHandler(new CancellationToken(canceled: true));
await Assert.ThrowsAsync<OperationCanceledException>(() => Test().Run(handler).AsTask());
Expand All @@ -20,15 +20,15 @@ public async Task Stub_CanceledToken_ShouldThrowOperationCanceledException()
[Fact]
public async Task DivergingWorkflow_CanceledToken_ShouldThrowOperationCanceledException()
{
async Eff Test()
static async Eff Test()
{
while (await ShouldContinue())
{
await Task.Delay(millisecondsDelay: 5);

}

async Eff<bool> ShouldContinue() => true;
static async Eff<bool> ShouldContinue() => true;
}

using var cts = new CancellationTokenSource(1_000);
Expand All @@ -39,7 +39,7 @@ async Eff Test()
[Fact]
public async Task CancellationTokenEffect_PassedToTask_ShouldThrowTaskCanceledException()
{
async Eff Test()
static async Eff Test()
{
var token = await CancellationTokenEffect.Value;
await Task.Delay(60_000, token);
Expand Down
4 changes: 2 additions & 2 deletions tests/Eff.Tests/CustomEffectHandler/CustomEffectHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ public class CustomEffectHandler : EffectHandler
{
private readonly DateTime _now;

public List<ExceptionLog> ExceptionLogs { get; } = new List<ExceptionLog>();
public List<ResultLog> TraceLogs { get; } = new List<ResultLog>();
public List<ExceptionLog> ExceptionLogs { get; } = [];
public List<ResultLog> TraceLogs { get; } = [];

public CustomEffectHandler(DateTime now)
{
Expand Down
6 changes: 3 additions & 3 deletions tests/Eff.Tests/CustomEffectHandler/CustomEffects.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ public interface IFuncEffect
}
public struct CustomEffect : IDateTimeNowEffect, IFuncEffect
{
public DateTimeNowEffect DateTimeNow() => new DateTimeNowEffect();
public DateTimeNowEffect DateTimeNow() => new();

public FuncEffect<TResult> Func<TResult>(Func<TResult> func) => new FuncEffect<TResult>(func);
public FuncEffect<TResult> Func<TResult>(Func<TResult> func) => new(func);

public FuncEffect<Unit> Action(Action action) => new FuncEffect<Unit>(() => { action(); return Unit.Value; });
public FuncEffect<Unit> Action(Action action) => new(() => { action(); return Unit.Value; });
}
16 changes: 8 additions & 8 deletions tests/Eff.Tests/CustomEffectHandlerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public class CustomEffectHandlerTests : EffectHandlerTests
[Fact]
public async Task AwaitCustomEffect()
{
async Eff<DateTime> Foo<T>()
static async Eff<DateTime> Foo<T>()
where T : struct, IDateTimeNowEffect
{
var y = await default(T).DateTimeNow().ConfigureAwait();
Expand All @@ -25,12 +25,12 @@ async Eff<DateTime> Foo<T>()
[Fact]
public async Task TestExceptionLog()
{
async Eff<int> Test(int x)
static async Eff<int> Test(int x)
{
var y = await Nested(x);
return y;

async Eff<int> Nested(int x)
static async Eff<int> Nested(int x)
{
return 1 / x;
}
Expand All @@ -46,12 +46,12 @@ async Eff<int> Nested(int x)
[Fact]
public async Task TestTraceLog()
{
async Eff<int> Test(int x)
static async Eff<int> Test(int x)
{
var y = await Nested(x);
return y;

async Eff<int> Nested(int x)
static async Eff<int> Nested(int x)
{
return x + 1;
}
Expand All @@ -68,7 +68,7 @@ async Eff<int> Nested(int x)
[Fact]
public async Task TestParametersLogging()
{
async Eff<int> Test(int x)
static async Eff<int> Test(int x)
{
var y = await Eff.FromResult(1);
return x + y;
Expand All @@ -87,7 +87,7 @@ async Eff<int> Test(int x)
[Fact]
public async Task TestLocalVariablesLogging()
{
async Eff<int> Test(int x)
static async Eff<int> Test(int x)
{
var y = await Eff.FromResult(1);
await Eff.CompletedEff;
Expand Down Expand Up @@ -137,7 +137,7 @@ async Eff<int> Foo<T>(int x)
[Fact]
public async Task AwaitCaptureStateEffect()
{
async Eff<int> Test(int x)
static async Eff<int> Test(int x)
{
var y = await Eff.FromResult(1);
await Eff.CompletedEff;
Expand Down
Loading