Skip to content

Commit 6fee214

Browse files
committed
Add CI. Update readme & logo.
1 parent ec822f6 commit 6fee214

5 files changed

Lines changed: 138 additions & 69 deletions

File tree

.github/workflows/ci.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
build_test:
11+
runs-on: windows-latest
12+
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v4
16+
17+
- name: Setup .NET SDK
18+
uses: actions/setup-dotnet@v5
19+
with:
20+
dotnet-version: '10.0.x'
21+
22+
- name: Show dotnet info
23+
run: dotnet --info
24+
25+
- name: Cache NuGet packages
26+
uses: actions/cache@v4
27+
with:
28+
path: ~/.nuget/packages
29+
key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj', '**/Directory.Packages.props', '**/global.json', '**/nuget.config') }}
30+
restore-keys: |
31+
nuget-${{ runner.os }}-
32+
33+
- name: Restore
34+
run: dotnet restore --nologo
35+
36+
- name: Build (Release)
37+
run: dotnet build --configuration Release --nologo -warnaserror
38+
39+
- name: Test (Release)
40+
run: dotnet test --configuration Release --nologo --no-build

README.md

Lines changed: 96 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,51 @@
1-
21
# NuExt.System
32

4-
`NuExt.System` is a **lightweight, production-ready foundation** for everyday .NET development. It brings together high-quality utilities for **asynchrony**, **lifetime management**, **threading primitives**, **high-performance spans/memory helpers**, **diagnostics**, and **collection helpers** — all with a strong focus on **performance**, **correctness**, and **developer ergonomics**.
5-
Use it to reduce boilerplate, standardize common patterns across projects, and keep code fast and clean across modern .NET and .NET Framework.
3+
`NuExt.System` is a **lightweight, production-ready foundation** for everyday .NET development. It brings together high-quality utilities for **asynchrony**, **lifetime management**, **threading primitives**, **high‑performance spans/memory helpers**, **diagnostics**, and **collection helpers** — all with a strong focus on **performance**, **correctness**, and **developer ergonomics**. Use it to reduce boilerplate, standardize common patterns across projects, and keep code fast and clean across modern .NET and .NET Framework.
4+
5+
[![NuGet](https://img.shields.io/nuget/v/NuExt.System.svg)](https://www.nuget.org/packages/NuExt.System)
6+
[![Build](https://github.com/IvanGit/NuExt.System/actions/workflows/ci.yml/badge.svg)](https://github.com/IvanGit/NuExt.System/actions/workflows/ci.yml)
7+
[![License](https://img.shields.io/github/license/IvanGit/NuExt.System?label=license)](https://github.com/IvanGit/NuExt.System/blob/main/LICENSE)
8+
[![Downloads](https://img.shields.io/nuget/dt/NuExt.System.svg)](https://www.nuget.org/packages/NuExt.System)
69

710
## Features
811

912
- **Asynchrony & lifetime**
10-
- Async locks and wait handles (`AsyncLock`, `ReentrantAsyncLock`, `AsyncWaitHandle`)
11-
- Disposable tooling (`Disposable`, `AggregateDisposable`, `AsyncDisposable`, `AggregateAsyncDisposable`, `AsyncLifetime`)
13+
- Async locks and wait handles: `AsyncLock`, `ReentrantAsyncLock`, `AsyncWaitHandle`
14+
- Disposable tooling: `Disposable`, `AggregateDisposable`, `AsyncDisposable`, `AggregateAsyncDisposable`, `AsyncLifetime`
1215
- **Threading & synchronization**
13-
- Reentrant async lock (context-aware), synchronization context helpers, thread-affine context
14-
- **High-performance spans & memory**
15-
- Backports/polyfills for `Span` / `MemoryExtensions` APIs (see below)
16-
- `ValueStringBuilder` / `ValueListBuilder<T>` for zero-allocation building
16+
- Reentrant async lock (contextaware), synchronizationcontext helpers, threadaffine flows
17+
- **Highperformance spans & memory**
18+
- **Backports/polyfills for `Span` / `MemoryExtensions` APIs** (see below)
19+
- `ValueStringBuilder` / `ValueListBuilder<T>` for zeroallocation building
1720
- **Collections & equality**
18-
- `ObservableDictionary<TKey, TValue>`, `ReferenceEqualityComparer` (polyfill), ArrayEqualityComparer, plus **many useful extension helpers**
19-
- **I/O & paths (cross-platform)**
20-
- `PathBuilder` (class, `IDisposable`) and `ValuePathBuilder` (ref struct) — platform-independent path builders
21+
- `ObservableDictionary<TKey, TValue>`, `ReferenceEqualityComparer` *(polyfill)*, `ArrayEqualityComparer<T>`, and **many useful extension helpers**
22+
- **I/O & paths (crossplatform)**
23+
- `PathBuilder` (class, `IDisposable`) and `ValuePathBuilder` (ref struct) — platformindependent path builders
2124
- `PathUtilities` — static helpers for common path operations
2225
- **Diagnostics & utilities**
23-
- `ProcessMonitor`, `PerformanceMonitor`, `EnumHelper<T>`, `TypeExtensions`, and more
26+
- `ProcessMonitor`, `PerformanceMonitor`, `EnumHelper<T>`, `TypeExtensions`, etc.
2427

2528
### Span / MemoryExtensions Polyfills
2629

27-
This package includes **polyfills (API backports)** for selected `Span` / `MemoryExtensions`-style APIs from newer .NET versions.
28-
On modern runtimes, it transparently uses the inbox implementations; on older runtimes, it provides compatible behavior with the same semantics.
30+
This package includes **polyfills (API backports)** for selected `Span` / `MemoryExtensions`‑style APIs from newer .NET versions. On modern runtimes, it transparently uses the inbox implementations; on older runtimes, it provides compatible behavior with the same semantics.
2931

3032
**What you get (highlights)**
3133
- Search & comparison: `Contains`, `SequenceEqual` (+ `IEqualityComparer<T>`)
3234
- Indexing: `IndexOf`, `LastIndexOf` (element / sequence)
33-
- Set-based search: `IndexOfAny`, `LastIndexOfAny`, `IndexOfAnyExcept`, `LastIndexOfAnyExcept`
34-
- Range-based: `IndexOfAnyInRange`, `IndexOfAnyExceptInRange`, `LastIndexOfAnyInRange`, `LastIndexOfAnyExceptInRange`
35-
- Utilities: `StartsWith`, `EndsWith`, `Replace` (in-place / copy), `Count`, `CountAny`
35+
- Setbased search: `IndexOfAny`, `LastIndexOfAny`, `IndexOfAnyExcept`, `LastIndexOfAnyExcept`
36+
- Rangebased: `IndexOfAnyInRange`, `IndexOfAnyExceptInRange`, `LastIndexOfAnyInRange`, `LastIndexOfAnyExceptInRange`
37+
- Utilities: `StartsWith`, `EndsWith`, `Replace` (inplace / copy), `Count`, `CountAny`
3638

3739
**Notes**
38-
- Allocation-free, performance-oriented; value types use bitwise fast paths where applicable.
39-
- Semantics match the .NET runtime APIs; custom comparers are honored when provided.
40+
- Allocationfree, performanceoriented; value types use bitwise fast paths where applicable.
41+
- Semantics mirror the .NET runtime APIs; custom comparers are honored when provided.
4042

4143
## Why NuExt.System?
4244

43-
- **Practical**: battle-tested building blocks you use every day
44-
- **Fast**: zero-alloc paths, tight loops, and careful branching profiles
45-
- **Consistent**: same behavior across modern .NET and .NET Framework
46-
- **Focused**: no heavy external dependencies or configuration
45+
- **Practical**battletested building blocks you use every day
46+
- **Fast**zeroalloc paths, tight loops, careful branching profiles
47+
- **Consistent**same behavior across modern .NET and .NET Framework
48+
- **Focused** no heavy external dependencies or configuration
4749

4850
### Compatibility
4951

@@ -60,61 +62,72 @@ On modern runtimes, it transparently uses the inbox implementations; on older ru
6062
- `System.Collections.Generic.ValueListBuilder<T>`
6163
- `System.Collections.Generic.ReferenceEqualityComparer` *(polyfill)*
6264
- `System.Collections.Generic.ArrayEqualityComparer<T>`
63-
- **Various useful extension helpers** (collections, delegates, enums, strings, exceptions)
65+
- **Various extension helpers** (collections, delegates, enums, strings, exceptions)
6466
- **Strings, spans, and memory**
6567
- `System.Text.ValueStringBuilder`
66-
- `System.CompatMemoryExtensions` (polyfills/backports)
67-
- **I/O & paths (cross-platform)**
68+
- `System.CompatMemoryExtensions` *(polyfills/backports)*
69+
- **I/O & paths (crossplatform)**
6870
- `System.IO.PathBuilder` *(class, `IDisposable` — mutable path builder)*
69-
- `System.IO.ValuePathBuilder` *(ref struct — high-performance mutable path builder)*
70-
- `System.IO.PathUtilities` *(static common path operations)*
71+
- `System.IO.ValuePathBuilder` *(ref struct — highperformance mutable path builder)*
72+
- `System.IO.PathUtilities` *(static common path operations)*
7173
- **Diagnostics & helpers**
7274
- `System.Diagnostics.ProcessMonitor`, `PerformanceMonitor`
7375
- `System.EnumHelper<T>`, `System.FormatUtils`, `System.HexConverter`
7476

75-
### Installation
77+
## Quick examples
7678

77-
Via [NuGet](https://www.nuget.org/):
79+
### 1) Reentrant async lock (with ExecutionContext best practices)
80+
```csharp
81+
var asyncLock = new System.Threading.ReentrantAsyncLock();
82+
var cts = new CancellationTokenSource();
7883

79-
```sh
80-
dotnet add package NuExt.System
81-
```
84+
// Synchronous section
85+
asyncLock.Acquire(() =>
86+
{
87+
// do work safely, reentry allowed on the same flow
88+
});
8289

83-
Or via Visual Studio:
90+
// Asynchronous section
91+
await asyncLock.AcquireAsync(async () =>
92+
{
93+
await DoAsyncWork();
94+
});
8495

85-
1. Go to `Tools -> NuGet Package Manager -> Manage NuGet Packages for Solution...`.
86-
2. Search for `NuExt.System`.
87-
3. Click "Install".
96+
// Avoid unintentionally flowing AsyncLocal into CT callbacks:
97+
using (ExecutionContext.SuppressFlow())
98+
{
99+
cts.Token.Register(() => asyncLock.Acquire(() =>
100+
{
101+
// safe callback body
102+
}));
103+
}
104+
```
105+
106+
### 2) Async lifetime + aggregated disposal
88107

89-
### ReentrantAsyncLock Internals
108+
```csharp
109+
var lifetime = new System.AsyncLifetime() { ContinueOnCapturedContext = true };
110+
lifetime.AddDisposable(new FileStream(path, FileMode.Open));
111+
lifetime.AddAsync(async () => await FlushBuffersAsync());
90112

91-
The `ReentrantAsyncLock` provides a context-aware reentrant async lock. It uses `AsyncLocal` to track ownership across awaits, allowing the same logical flow to re-enter without deadlocks.
113+
await lifetime.DisposeAsync(); // disposes in the right order, async‑aware
114+
```
92115

93-
In scenarios that capture **ExecutionContext** (e.g., `CancellationToken.Register`), prefer suppressing the flow to avoid leaking `AsyncLocal` state into callbacks:
116+
### 3) Zero‑alloc string building with `ValueStringBuilder`
94117

95118
```csharp
96-
var asyncLock = new ReentrantAsyncLock();
97-
var cts = new CancellationTokenSource();
119+
Span<char> initial = stackalloc char[128];
120+
var sb = new System.Text.ValueStringBuilder(initial);
98121

99-
asyncLock.Acquire(() =>
100-
{
101-
//Don't capture the current ExecutionContext and its AsyncLocals for CancellationToken.Register
102-
using (ExecutionContext.SuppressFlow())
103-
{
104-
cts.Token.Register(() => asyncLock.Acquire(() =>
105-
{
106-
// user code
107-
}));
108-
}
109-
//The current ExecutionContext is restored after exiting the using block
110-
});
122+
sb.Append("User: ");
123+
sb.Append(userName);
124+
sb.Append(", Items: ");
125+
sb.Append(itemCount);
111126

112-
asyncLock.Acquire(() => cts.Cancel());
127+
string result = sb.ToString(); // minimal allocations
113128
```
114129

115-
### Usage Examples
116-
117-
#### `ValueListBuilder<T>` and `ValueTask.WhenAll`
130+
### 4) `ValueListBuilder<T>` and `ValueTask.WhenAll`
118131

119132
```csharp
120133
public class Example
@@ -164,7 +177,7 @@ public class Example
164177
}
165178
```
166179

167-
#### `ValueListBuilder<T>` and `ValueTask.WhenAll<TResult>`
180+
### 5) `ValueListBuilder<T>` and `ValueTask.WhenAll<TResult>`
168181

169182
```csharp
170183
public class Example
@@ -218,22 +231,38 @@ public class Example
218231
}
219232
```
220233

221-
For comprehensive examples of how to use the package, see:
234+
## Installation
235+
236+
Via [NuGet](https://www.nuget.org/):
237+
238+
```sh
239+
dotnet add package NuExt.System
240+
```
241+
242+
Or via Visual Studio:
243+
244+
1. Go to `Tools -> NuGet Package Manager -> Manage NuGet Packages for Solution...`.
245+
2. Search for `NuExt.System`.
246+
3. Click "Install".
247+
248+
## Ecosystem
222249

250+
- [NuExt.Minimal.Mvvm](https://github.com/IvanGit/NuExt.Minimal.Mvvm)
251+
- [NuExt.Minimal.Mvvm.Wpf](https://github.com/IvanGit/NuExt.Minimal.Mvvm.Wpf)
252+
- [NuExt.Minimal.Mvvm.MahApps.Metro](https://github.com/IvanGit/NuExt.Minimal.Mvvm.MahApps.Metro)
253+
- [NuExt.System.Data](https://github.com/IvanGit/NuExt.System.Data)
223254
- [NuExt.System.Data.SQLite](https://github.com/IvanGit/NuExt.System.Data.SQLite)
224255
- [NuExt.DevExpress.Mvvm](https://github.com/IvanGit/NuExt.DevExpress.Mvvm)
225256
- [NuExt.DevExpress.Mvvm.MahApps.Metro](https://github.com/IvanGit/NuExt.DevExpress.Mvvm.MahApps.Metro)
226-
- [NuExt.Minimal.Mvvm.Wpf](https://github.com/IvanGit/NuExt.Minimal.Mvvm.Wpf)
227-
- [NuExt.Minimal.Mvvm.MahApps.Metro](https://github.com/IvanGit/NuExt.Minimal.Mvvm.MahApps.Metro)
228257

229-
### Acknowledgements
258+
## Notes & acknowledgements
230259

231-
Includes code derived from the .NET Runtime, licensed under the MIT License. The original source code can be found in the [.NET Runtime GitHub repository](https://github.com/dotnet/runtime).
260+
Some implementations are derived from the .NET Runtime (MIT). See LICENSE and source comments for attributions.
232261

233-
### Contributing
262+
## Contributing
234263

235264
Issues and PRs are welcome. Keep changes minimal and performance-conscious.
236265

237-
### License
266+
## License
238267

239268
MIT. See LICENSE.

logo128.png

-18.4 KB
Binary file not shown.

logo256.png

61.4 KB
Loading

src/NuExt.System.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ System.Collections.ObjectModel.ObservableDictionary&lt;TKey, TValue&gt;
3838
<GenerateDocumentationFile>True</GenerateDocumentationFile>
3939
<NoWarn>$(NoWarn);1591;NETSDK1233</NoWarn>
4040
<PackageReadmeFile>README.md</PackageReadmeFile>
41-
<PackageIcon>logo128.png</PackageIcon>
41+
<PackageIcon>logo256.png</PackageIcon>
4242
<PackageProjectUrl>https://github.com/IvanGit/NuExt.System</PackageProjectUrl>
4343
</PropertyGroup>
4444

@@ -55,7 +55,7 @@ System.Collections.ObjectModel.ObservableDictionary&lt;TKey, TValue&gt;
5555
</ItemGroup>
5656

5757
<ItemGroup>
58-
<None Include="..\logo128.png" Pack="true" PackagePath="\" />
58+
<None Include="..\logo256.png" Pack="true" PackagePath="\" />
5959
<None Include=".\..\README.md" Pack="true" PackagePath="\" />
6060
</ItemGroup>
6161

0 commit comments

Comments
 (0)