diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 971234b..394a0e4 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -13,7 +13,7 @@ on: name: ci-build env: - DOTNET_VERSION: 9.0.x + DOTNET_VERSION: 10.0.x REGISTRY: ghcr.io jobs: diff --git a/MinimalEvents/MinimalEvents.csproj b/MinimalEvents/MinimalEvents.csproj index 4c714a3..50fc56f 100644 --- a/MinimalEvents/MinimalEvents.csproj +++ b/MinimalEvents/MinimalEvents.csproj @@ -5,7 +5,7 @@ enable OpenShock.MinimalEvents OpenShock.MinimalEvents - net9.0;netstandard2.1 + net10.0;netstandard2.1 true OpenShock.MinimalEvents MinimalEvents @@ -15,14 +15,14 @@ README.md https://github.com/OpenShock/MinimalEvents https://openshock.org - 13 + latest MinimalEvents true snupkg - 0.0.1 - 0.0.1 - 0.0.1 + 1.0.0 + 1.0.0 + 1.0.0 diff --git a/MinimalEventsTests/MinimalEventsTests.csproj b/MinimalEventsTests/MinimalEventsTests.csproj index d784529..9ef024e 100644 --- a/MinimalEventsTests/MinimalEventsTests.csproj +++ b/MinimalEventsTests/MinimalEventsTests.csproj @@ -1,12 +1,13 @@ - net9.0 + net10.0 enable enable OpenShock OpenShock.MinimalEvents.Tests OpenShock.MinimalEvents.Tests + false diff --git a/README.md b/README.md index e098fc3..9f7ec31 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,99 @@ -# Minimal Events +# Minimal Events -Minimal Events is a very opinionated event library designed to be used in OpenShock projects. +Minimal Events is a very opinionated, minimal and modern event library designed to be used in OpenShock projects. -Inspired by System.Reactive (RxNET) \ No newline at end of file +Inspired by [System.Reactive (Rx.NET)](https://github.com/dotnet/reactive), it provides a tiny observable-style API for subscribing to and invoking events, both synchronously and asynchronously. + +## Features + +- Synchronous and asynchronous events +- Optional strongly-typed event arguments +- Subscriptions are managed via `IDisposable` / `IAsyncDisposable` — dispose to unsubscribe +- Thread-safe subscribe/unsubscribe backed by immutable handler lists +- Targets `net10.0` and `netstandard2.1` + +## Installation + +```sh +dotnet add package OpenShock.MinimalEvents +``` + +## Usage + +### Synchronous + +```csharp +using OpenShock.MinimalEvents; + +var onTick = new MinimalEvent(); + +using (onTick.Subscribe(() => Console.WriteLine("tick"))) +{ + onTick.Invoke(); // prints "tick" +} + +onTick.Invoke(); // nothing — the subscription was disposed +``` + +### Synchronous with an argument + +```csharp +var onMessage = new MinimalEvent(); + +using var subscription = onMessage.Subscribe(msg => Console.WriteLine($"got: {msg}")); + +onMessage.Invoke("hello"); // prints "got: hello" +``` + +### Asynchronous + +```csharp +var onStarted = new AsyncMinimalEvent(); + +await using var subscription = await onStarted.SubscribeAsync(async () => +{ + await Task.Delay(10); + Console.WriteLine("started"); +}); + +await onStarted.InvokeAsyncParallel(); // invokes all handlers in parallel +``` + +### Asynchronous with an argument + +```csharp +var onValue = new AsyncMinimalEvent(); + +await using var subscription = await onValue.SubscribeAsync(async value => +{ + await Task.Delay(10); + Console.WriteLine($"value: {value}"); +}); + +await onValue.InvokeAsyncParallel(42); +``` + +Async handlers are invoked in parallel; if any handler throws, the aggregated exception is rethrown once all handlers have completed. + +## Exposing events + +To expose an event without letting consumers invoke it, return the matching observable interface: + +- `IMinimalEventObservable` / `IMinimalEventObservable` +- `IAsyncMinimalEventObservable` / `IAsyncMinimalEventObservable` + +```csharp +public sealed class Connection +{ + private readonly AsyncMinimalEvent _onMessage = new(); + + // Consumers can subscribe, but only Connection can invoke. + public IAsyncMinimalEventObservable OnMessage => _onMessage; + + internal Task RaiseAsync(string message) => _onMessage.InvokeAsyncParallel(message); +} +``` + +## License + +[MIT](LICENSE) diff --git a/global.json b/global.json new file mode 100644 index 0000000..3140116 --- /dev/null +++ b/global.json @@ -0,0 +1,5 @@ +{ + "test": { + "runner": "Microsoft.Testing.Platform" + } +}