Skip to content

Commit b2cdfc1

Browse files
committed
Release 5.26.0
1 parent f0dd7b8 commit b2cdfc1

File tree

55 files changed

+736
-613
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+736
-613
lines changed

CHANGELOG.md

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,33 @@
11
Release Notes
22
====
33

4+
# 10-22-2025
5+
<a href="https://www.nuget.org/packages/dotnext/5.26.0">DotNext 5.26.0</a>
6+
* Introduced `DotNext.IO.ModernStream` class that derives from [Stream](https://learn.microsoft.com/en-us/dotnet/api/system.io.stream) and implements many of the methods introduced since .NET Framework 1.1 by default in a modern way, requiring only minimal subset of core methods to be implemented by the derived class
7+
* Removed async state machine allocations for ad-hoc streams returned by `StreamSource` factory methods
8+
9+
<a href="https://www.nuget.org/packages/dotnext.metaprogramming/5.26.0">DotNext.Metaprogramming 5.26.0</a>
10+
* Updated dependencies
11+
12+
<a href="https://www.nuget.org/packages/dotnext.unsafe/5.26.0">DotNext.Unsafe 5.26.0</a>
13+
* Updated dependencies
14+
15+
<a href="https://www.nuget.org/packages/dotnext.threading/5.26.0">DotNext.Threading 5.26.0</a>
16+
* Improved support of timeouts in `CancellationTokenMultiplexer`. The scope object now has explicit property to detect whether the multiplexed token source is cancelled due to timeout
17+
18+
<a href="https://www.nuget.org/packages/dotnext.io/5.26.0">DotNext.IO 5.26.0</a>
19+
* Migration to `ModernStream` class
20+
21+
<a href="https://www.nuget.org/packages/dotnext.net.cluster/5.26.0">DotNext.Net.Cluster 5.26.0</a>
22+
* Migration of Raft implementation to `CancellationTokenMultiplexer`
23+
24+
<a href="https://www.nuget.org/packages/dotnext.aspnetcore.cluster/5.26.0">DotNext.AspNetCore.Cluster 5.26.0</a>
25+
* Migration of Raft implementation to `CancellationTokenMultiplexer`
26+
27+
<a href="https://www.nuget.org/packages/dotnext.maintenanceservices/0.5.0">DotNext.MaintenanceServices 0.7.0</a>
28+
* Migration to `System.CommandLine` release candidate
29+
* Added custom parser configuration (`ParserConfiguration` class) that can be registered in DI
30+
431
# 09-29-2025
532
<a href="https://www.nuget.org/packages/dotnext.threading/5.25.2">DotNext.Threading 5.25.2</a>
633
* Fixed [272](https://github.com/dotnet/dotNext/pull/272)
@@ -17,10 +44,10 @@ Release Notes
1744
* Various performance improvements
1845

1946
<a href="https://www.nuget.org/packages/dotnext.metaprogramming/5.25.0">DotNext.Metaprogramming 5.25.0</a>
20-
* Fixed mutability modifiers for properties of `UnmanagedMemory<T>` type
47+
* Updated dependencies
2148

2249
<a href="https://www.nuget.org/packages/dotnext.unsafe/5.25.0">DotNext.Unsafe 5.25.0</a>
23-
* Updated dependencies
50+
* Fixed mutability modifiers for properties of `UnmanagedMemory<T>` type
2451

2552
<a href="https://www.nuget.org/packages/dotnext.threading/5.25.0">DotNext.Threading 5.25.0</a>
2653
* Added optional hard concurrency limit for async lock primitives

README.md

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,33 @@ All these things are implemented in 100% managed code on top of existing .NET AP
4444
* [NuGet Packages](https://www.nuget.org/profiles/rvsakno)
4545

4646
# What's new
47-
Release Date: 09-29-2025
47+
Release Date: 10-22-2025
4848

49-
<a href="https://www.nuget.org/packages/dotnext.threading/5.25.2">DotNext.Threading 5.25.2</a>
50-
* Fixed [272](https://github.com/dotnet/dotNext/pull/272)
49+
<a href="https://www.nuget.org/packages/dotnext/5.26.0">DotNext 5.26.0</a>
50+
* Introduced `DotNext.IO.ModernStream` class that derives from [Stream](https://learn.microsoft.com/en-us/dotnet/api/system.io.stream) and implements many of the methods introduced since .NET Framework 1.1 by default in a modern way, requiring only minimal subset of core methods to be implemented by the derived class
51+
* Removed async state machine allocations for ad-hoc streams returned by `StreamSource` factory methods
5152

52-
<a href="https://www.nuget.org/packages/dotnext.net.cluster/5.25.2">DotNext.Net.Cluster 5.25.2</a>
53-
* Forced upgrade to newer `DotNext.Threading` library
53+
<a href="https://www.nuget.org/packages/dotnext.metaprogramming/5.26.0">DotNext.Metaprogramming 5.26.0</a>
54+
* Updated dependencies
5455

55-
<a href="https://www.nuget.org/packages/dotnext.aspnetcore.cluster/5.25.2">DotNext.AspNetCore.Cluster 5.25.2</a>
56-
* Forced upgrade to newer `DotNext.Threading` library
56+
<a href="https://www.nuget.org/packages/dotnext.unsafe/5.26.0">DotNext.Unsafe 5.26.0</a>
57+
* Updated dependencies
58+
59+
<a href="https://www.nuget.org/packages/dotnext.threading/5.26.0">DotNext.Threading 5.26.0</a>
60+
* Improved support of timeouts in `CancellationTokenMultiplexer`. The scope object now has explicit property to detect whether the multiplexed token source is cancelled due to timeout
61+
62+
<a href="https://www.nuget.org/packages/dotnext.io/5.26.0">DotNext.IO 5.26.0</a>
63+
* Migration to `ModernStream` class
64+
65+
<a href="https://www.nuget.org/packages/dotnext.net.cluster/5.26.0">DotNext.Net.Cluster 5.26.0</a>
66+
* Migration of Raft implementation to `CancellationTokenMultiplexer`
67+
68+
<a href="https://www.nuget.org/packages/dotnext.aspnetcore.cluster/5.26.0">DotNext.AspNetCore.Cluster 5.26.0</a>
69+
* Migration of Raft implementation to `CancellationTokenMultiplexer`
70+
71+
<a href="https://www.nuget.org/packages/dotnext.maintenanceservices/0.5.0">DotNext.MaintenanceServices 0.7.0</a>
72+
* Migration to `System.CommandLine` release candidate
73+
* Added custom parser configuration (`ParserConfiguration` class) that can be registered in DI
5774

5875
Changelog for previous versions located [here](./CHANGELOG.md).
5976

src/Directory.Packages.props

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
</PropertyGroup>
55
<ItemGroup>
66
<!--Compile-time dependencies-->
7-
<PackageVersion Include="Fody" Version="6.8.0" />
8-
<PackageVersion Include="InlineIL.Fody" Version="1.7.4" />
7+
<PackageVersion Include="Fody" Version="6.9.3" />
8+
<PackageVersion Include="InlineIL.Fody" Version="1.10.1" />
99
<PackageVersion Include="Microsoft.FASTER.Core" Version="2.6.5" />
1010
</ItemGroup>
1111
<ItemGroup>
1212
<!--System packages-->
1313
<PackageVersion Include="System.Collections.Immutable" Version="8.0.0" />
14-
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta5.25306.1" />
14+
<PackageVersion Include="System.CommandLine" Version="2.0.0-rc.2.25502.107" />
1515
<PackageVersion Include="System.IO.Hashing" Version="8.0.0" />
1616
<PackageVersion Include="System.IO.Pipelines" Version="8.0.0" />
1717
<PackageVersion Include="System.Resources.Extensions" Version="8.0.0" />
@@ -20,28 +20,28 @@
2020
</ItemGroup>
2121
<ItemGroup>
2222
<!--Microsoft packages-->
23-
<PackageVersion Include="Microsoft.AspNetCore.Connections.Abstractions" Version="8.0.16" />
23+
<PackageVersion Include="Microsoft.AspNetCore.Connections.Abstractions" Version="8.0.21" />
2424
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.3" />
2525
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.1" />
2626
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="8.0.1" />
2727
<PackageVersion Include="Microsoft.Extensions.Http" Version="8.0.1" />
2828
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
2929
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" />
3030
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
31-
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
32-
<PackageVersion Include="MSTest.Engine" Version="1.0.0-alpha.25277.3" />
33-
<PackageVersion Include="MSTest.SourceGeneration" Version="1.0.0-alpha.25277.3" />
34-
<PackageVersion Include="Microsoft.Testing.Extensions.TrxReport" Version="1.7.1" />
35-
<PackageVersion Include="Microsoft.Testing.Platform.MSBuild" Version="1.7.1" />
36-
<PackageVersion Include="MSTest.TestFramework" Version="3.9.1" />
37-
<PackageVersion Include="MSTest.Analyzers" Version="3.9.1" />
31+
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.0" />
32+
<PackageVersion Include="MSTest.Engine" Version="2.0.0-alpha.25514.6" />
33+
<PackageVersion Include="MSTest.SourceGeneration" Version="2.0.0-alpha.25514.6" />
34+
<PackageVersion Include="Microsoft.Testing.Extensions.TrxReport" Version="2.0.1" />
35+
<PackageVersion Include="Microsoft.Testing.Platform.MSBuild" Version="2.0.1" />
36+
<PackageVersion Include="MSTest.TestFramework" Version="4.0.1" />
37+
<PackageVersion Include="MSTest.Analyzers" Version="4.0.1" />
3838
</ItemGroup>
3939
<ItemGroup>
4040
<!--Misc packages-->
41-
<PackageVersion Include="BenchmarkDotNet" Version="0.15.0" />
41+
<PackageVersion Include="BenchmarkDotNet" Version="0.15.4" />
4242
<PackageVersion Include="FastMember.Signed" Version="1.5.0" />
4343
<PackageVersion Include="xunit" Version="2.9.3" />
44-
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.0" />
44+
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
4545
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
4646
</ItemGroup>
4747
</Project>

src/DotNext.AotTests/DelegateHelpersTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
namespace DotNext;
22

3+
[TestClass]
34
public class DelegateHelpersTests
45
{
56
[TestMethod]

src/DotNext.AotTests/Runtime/BoxedValueTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public void Unwrap()
2323
Assert.AreEqual(42, BoxedValue<int>.GetTypedReference(obj));
2424

2525
obj = string.Empty;
26-
Assert.ThrowsException<ArgumentException>(() => BoxedValue<int>.GetTypedReference(obj));
26+
Assert.Throws<ArgumentException>(() => BoxedValue<int>.GetTypedReference(obj));
2727
}
2828

2929
[TestMethod]

src/DotNext.AotTests/Runtime/ValueReferenceTests.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ public void MutableEmptyRef()
9090
Span<string> span = reference;
9191
Assert.IsTrue(span.IsEmpty);
9292

93-
Assert.ThrowsException<NullReferenceException>((Func<string>)reference);
94-
Assert.ThrowsException<NullReferenceException>(((Action<string>)reference).Bind(string.Empty));
93+
Assert.Throws<NullReferenceException>((Func<string>)reference);
94+
Assert.Throws<NullReferenceException>(((Action<string>)reference).Bind(string.Empty));
9595
}
9696

9797
[TestMethod]
@@ -104,7 +104,7 @@ public void ImmutableEmptyRef()
104104
ReadOnlySpan<string> span = reference;
105105
Assert.IsTrue(span.IsEmpty);
106106

107-
Assert.ThrowsException<NullReferenceException>((Func<string>)reference);
107+
Assert.Throws<NullReferenceException>((Func<string>)reference);
108108
}
109109

110110
[TestMethod]
@@ -129,8 +129,8 @@ private static Func<T> ToFunc<TSupplier, T>(TSupplier supplier)
129129
public void IncorrectReference()
130130
{
131131
byte[] empty = [];
132-
Assert.ThrowsException<ArgumentOutOfRangeException>(() => new ValueReference<byte>(empty, ref MemoryMarshal.GetArrayDataReference(empty)));
133-
Assert.ThrowsException<ArgumentOutOfRangeException>(() => new ReadOnlyValueReference<byte>(empty, ref MemoryMarshal.GetArrayDataReference(empty)));
132+
Assert.Throws<ArgumentOutOfRangeException>(() => new ValueReference<byte>(empty, ref MemoryMarshal.GetArrayDataReference(empty)));
133+
Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlyValueReference<byte>(empty, ref MemoryMarshal.GetArrayDataReference(empty)));
134134
}
135135

136136
[TestMethod]
@@ -153,7 +153,7 @@ public void BoxedValueInterop()
153153
public void ArrayCovariance()
154154
{
155155
string[] array = ["a", "b"];
156-
Assert.ThrowsException<ArrayTypeMismatchException>(() => new ValueReference<object>(array, 0));
156+
Assert.Throws<ArrayTypeMismatchException>(() => new ValueReference<object>(array, 0));
157157

158158
var roRef = new ReadOnlyValueReference<object>(array, 1);
159159
Assert.AreEqual("b", roRef.Value);

src/DotNext.IO/DotNext.IO.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<Authors>.NET Foundation and Contributors</Authors>
1212
<Company />
1313
<Product>.NEXT Family of Libraries</Product>
14-
<VersionPrefix>5.25.0</VersionPrefix>
14+
<VersionPrefix>5.26.0</VersionPrefix>
1515
<VersionSuffix></VersionSuffix>
1616
<AssemblyName>DotNext.IO</AssemblyName>
1717
<PackageLicenseExpression>MIT</PackageLicenseExpression>

src/DotNext.IO/IO/FileBufferingWriter.cs

Lines changed: 1 addition & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ namespace DotNext.IO;
2121
/// returned <see cref="Memory{T}"/> instance references bytes in memory. Otherwise,
2222
/// it references memory-mapped file.
2323
/// </remarks>
24-
public sealed partial class FileBufferingWriter : Stream, IBufferWriter<byte>, IGrowableBuffer<byte>, IFlushable
24+
public sealed partial class FileBufferingWriter : ModernStream, IBufferWriter<byte>, IGrowableBuffer<byte>
2525
{
2626
[StructLayout(LayoutKind.Auto)]
2727
private readonly struct ReadSession : IDisposable
@@ -472,28 +472,6 @@ public override void Write(ReadOnlySpan<byte> input)
472472
[MemberNotNull(nameof(fileBackend))]
473473
private void EnsureBackingStore() => fileBackend ??= fileProvider.CreateBackingFileHandle(position, out fileName);
474474

475-
/// <inheritdoc/>
476-
public override void Write(byte[] data, int offset, int count)
477-
{
478-
ValidateBufferArguments(data, offset, count);
479-
Write(new ReadOnlySpan<byte>(data, offset, count));
480-
}
481-
482-
/// <inheritdoc/>
483-
public override Task WriteAsync(byte[] data, int offset, int count, CancellationToken token)
484-
=> WriteAsync(new ReadOnlyMemory<byte>(data, offset, count), token).AsTask();
485-
486-
/// <inheritdoc/>
487-
public override void WriteByte(byte value)
488-
=> Write(new(ref value));
489-
490-
/// <inheritdoc/>
491-
public override IAsyncResult BeginWrite(byte[] data, int offset, int count, AsyncCallback? callback, object? state)
492-
=> TaskToAsyncResult.Begin(WriteAsync(data, offset, count), callback, state);
493-
494-
/// <inheritdoc/>
495-
public override void EndWrite(IAsyncResult ar) => TaskToAsyncResult.End(ar);
496-
497475
/// <inheritdoc cref="Stream.Flush()"/>
498476
public override void Flush() => Flush(flushToDisk: false);
499477

@@ -557,34 +535,14 @@ public ValueTask FlushAsync(bool flushToDisk, CancellationToken token = default)
557535
public override Task FlushAsync(CancellationToken token)
558536
=> FlushAsync(flushToDisk: false, token).AsTask();
559537

560-
/// <inheritdoc/>
561-
public override int ReadByte()
562-
=> throw new NotSupportedException();
563-
564-
/// <inheritdoc/>
565-
public override int Read(byte[] data, int offset, int count)
566-
=> throw new NotSupportedException();
567-
568538
/// <inheritdoc/>
569539
public override int Read(Span<byte> data)
570540
=> throw new NotSupportedException();
571541

572-
/// <inheritdoc/>
573-
public override Task<int> ReadAsync(byte[] data, int offset, int count, CancellationToken token)
574-
=> Task.FromException<int>(new NotSupportedException());
575-
576542
/// <inheritdoc/>
577543
public override ValueTask<int> ReadAsync(Memory<byte> data, CancellationToken token = default)
578544
=> ValueTask.FromException<int>(new NotSupportedException());
579545

580-
/// <inheritdoc/>
581-
public override IAsyncResult BeginRead(byte[] data, int offset, int count, AsyncCallback? callback, object? state)
582-
=> throw new NotSupportedException();
583-
584-
/// <inheritdoc/>
585-
public override int EndRead(IAsyncResult asyncResult)
586-
=> throw new InvalidOperationException();
587-
588546
/// <inheritdoc/>
589547
public override void SetLength(long value)
590548
=> throw new NotSupportedException();

src/DotNext.IO/IO/PoolingBufferedStream.cs

Lines changed: 1 addition & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System.Diagnostics;
22
using System.Diagnostics.CodeAnalysis;
3-
using System.Runtime.CompilerServices;
43

54
namespace DotNext.IO;
65

@@ -15,7 +14,7 @@ namespace DotNext.IO;
1514
/// </remarks>
1615
/// <param name="stream">The underlying stream to be buffered.</param>
1716
/// <param name="leaveOpen"><see langword="true"/> to leave <paramref name="stream"/> open after the object is disposed; otherwise, <see langword="false"/>.</param>
18-
public sealed class PoolingBufferedStream(Stream stream, bool leaveOpen = false) : Stream, IBufferedWriter, IFlushable, IBufferedReader
17+
public sealed class PoolingBufferedStream(Stream stream, bool leaveOpen = false) : ModernStream, IBufferedWriter, IBufferedReader
1918
{
2019
private const int MinBufferSize = 16;
2120
private const int DefaultBufferSize = 4096;
@@ -323,18 +322,6 @@ private void WriteCore(ReadOnlySpan<byte> data)
323322
}
324323
}
325324

326-
/// <inheritdoc/>
327-
public override void Write(byte[] data, int offset, int count)
328-
{
329-
ValidateBufferArguments(data, offset, count);
330-
331-
Write(new ReadOnlySpan<byte>(data, offset, count));
332-
}
333-
334-
/// <inheritdoc/>
335-
public override void WriteByte(byte value)
336-
=> Write(new ReadOnlySpan<byte>(in value));
337-
338325
/// <inheritdoc cref="Stream.WriteAsync(ReadOnlyMemory{byte}, CancellationToken)"/>
339326
public override ValueTask WriteAsync(ReadOnlyMemory<byte> data, CancellationToken token = default)
340327
{
@@ -419,17 +406,6 @@ private async ValueTask WriteWithBufferAsync(ReadOnlyMemory<byte> data, Cancella
419406
Reset();
420407
}
421408

422-
/// <inheritdoc/>
423-
public override Task WriteAsync(byte[] data, int offset, int count, CancellationToken token)
424-
=> WriteAsync(new ReadOnlyMemory<byte>(data, offset, count), token).AsTask();
425-
426-
/// <inheritdoc/>
427-
public override IAsyncResult BeginWrite(byte[] data, int offset, int count, AsyncCallback? callback, object? state)
428-
=> TaskToAsyncResult.Begin(WriteAsync(data, offset, count), callback, state);
429-
430-
/// <inheritdoc/>
431-
public override void EndWrite(IAsyncResult asyncResult) => TaskToAsyncResult.End(asyncResult);
432-
433409
private ReadOnlyMemory<byte> MemoryToRead => buffer.Memory[readPosition..readLength];
434410

435411
private int ReadFromBuffer(Span<byte> destination)
@@ -504,14 +480,6 @@ private int ReadCore(Span<byte> data)
504480
return bytesRead;
505481
}
506482

507-
/// <inheritdoc/>
508-
public override int Read(byte[] data, int offset, int count)
509-
{
510-
ValidateBufferArguments(data, offset, count);
511-
512-
return Read(data.AsSpan(offset, count));
513-
}
514-
515483
/// <inheritdoc cref="Stream.ReadAsync(Memory{byte}, CancellationToken)"/>
516484
public override ValueTask<int> ReadAsync(Memory<byte> data, CancellationToken token = default)
517485
{
@@ -538,10 +506,6 @@ public override ValueTask<int> ReadAsync(Memory<byte> data, CancellationToken to
538506
return task;
539507
}
540508

541-
/// <inheritdoc/>
542-
public override Task<int> ReadAsync(byte[] data, int offset, int count, CancellationToken token)
543-
=> ReadAsync(data.AsMemory(offset, count), token).AsTask();
544-
545509
private async ValueTask<int> ReadCoreAsync(Memory<byte> data, CancellationToken token)
546510
{
547511
Debug.Assert(stream is not null);
@@ -663,13 +627,6 @@ private bool PrepareReadBuffer(out Memory<byte> readBuffer)
663627
return true;
664628
}
665629

666-
/// <inheritdoc/>
667-
public override IAsyncResult BeginRead(byte[] data, int offset, int count, AsyncCallback? callback, object? state)
668-
=> TaskToAsyncResult.Begin(ReadAsync(data, offset, count), callback, state);
669-
670-
/// <inheritdoc/>
671-
public override int EndRead(IAsyncResult asyncResult) => TaskToAsyncResult.End<int>(asyncResult);
672-
673630
/// <inheritdoc cref="Stream.FlushAsync(CancellationToken)"/>
674631
public override Task FlushAsync(CancellationToken token)
675632
{
@@ -758,13 +715,6 @@ private long SeekNoWriteBuffer(long offset, SeekOrigin origin)
758715
return newPos;
759716
}
760717

761-
/// <inheritdoc/>
762-
public override int ReadByte()
763-
{
764-
Unsafe.SkipInit(out byte value);
765-
return Read(new Span<byte>(ref value)) > 0 ? value : -1;
766-
}
767-
768718
private void EnsureWriteBufferIsEmpty()
769719
{
770720
if (writePosition is not 0)

0 commit comments

Comments
 (0)