Skip to content

Commit

Permalink
Release 5.17.0
Browse files Browse the repository at this point in the history
  • Loading branch information
sakno committed Dec 29, 2024
1 parent 931fb6c commit 09613ee
Show file tree
Hide file tree
Showing 90 changed files with 3,188 additions and 804 deletions.
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,42 @@
Release Notes
====

# 12-29-2024
This release is aimed to improve AOT compatibility. All the examples in the repo are now AOT compatible.
<a href="https://www.nuget.org/packages/dotnext/5.17.0">DotNext 5.17.0</a>
* Fixed AOT compatibility in `TaskType` class
* Added [ISpanFormattable](https://learn.microsoft.com/en-us/dotnet/api/system.ispanformattable) and [IParsable&lt;T&gt;](https://learn.microsoft.com/en-us/dotnet/api/system.iparsable-1) interfaces to `HttpEndPoint`
* Introduced `TryEncodeAsUtf8` extension method for `SpanWriter<T>`
* Added more factory methods to `DotNext.Buffers.Memory` class to create [ReadOnlySequence&lt;T&gt;](https://learn.microsoft.com/en-us/dotnet/api/system.buffers.readonlysequence-1)
* `Intrinsics.KeepAlive` is introduced for value types
* Added `Synchronization.Wait()` synchronous methods for blocking wait of [value tasks](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.valuetask) without wait handles

<a href="https://www.nuget.org/packages/dotnext.metaprogramming/5.17.0">DotNext.Metaprogramming 5.17.0</a>
* Updated dependencies

<a href="https://www.nuget.org/packages/dotnext.unsafe/5.17.0">DotNext.Unsafe 5.17.0</a>
* Improved AOT support
* Fixed finalizer for unmanaged memory manager that allows to release the allocated unmanaged memory automatically by GC to avoid memory leak
* Updated dependencies

<a href="https://www.nuget.org/packages/dotnext.threading/5.17.0">DotNext.Threading 5.17.0</a>
* Improved AOT support

<a href="https://www.nuget.org/packages/dotnext.io/5.17.0">DotNext.IO 5.17.0</a>
* Reduced memory consumption for applications that use `FileReader` and `FileWriter` classes. These classes are now implemented by using lazy buffer pattern. It means that the different instances can reuse the same buffer taken from the pool
* Fixed [255](https://github.com/dotnet/dotNext/issues/255)
* `PoolingBufferedStream` is introduced to replace classic [BufferedStream](https://learn.microsoft.com/en-us/dotnet/api/system.io.bufferedstream). This class supports memory pooling and implements lazy buffer pattern

<a href="https://www.nuget.org/packages/dotnext.net.cluster/5.17.0">DotNext.Net.Cluster 5.17.0</a>
* Improved AOT support

<a href="https://www.nuget.org/packages/dotnext.aspnetcore.cluster/5.17.0">DotNext.AspNetCore.Cluster 5.17.0</a>
* Improved AOT support
* Fixed [254](https://github.com/dotnet/dotNext/issues/254)

<a href="https://www.nuget.org/packages/dotnext.maintenanceservices/0.5.0">DotNext.MaintenanceServices 0.5.0</a>
* Improved AOT support

# 12-07-2024
<a href="https://www.nuget.org/packages/dotnext/5.16.0">DotNext 5.16.1</a>
* Added [LEB128](https://en.wikipedia.org/wiki/LEB128) encoder and decoder as a public API. See `DotNext.Buffers.Binary.Leb128<T>` type for more information
Expand Down
50 changes: 29 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,34 +44,42 @@ All these things are implemented in 100% managed code on top of existing .NET AP
* [NuGet Packages](https://www.nuget.org/profiles/rvsakno)

# What's new
Release Date: 12-07-2024

<a href="https://www.nuget.org/packages/dotnext/5.16.0">DotNext 5.16.1</a>
* Added [LEB128](https://en.wikipedia.org/wiki/LEB128) encoder and decoder as a public API. See `DotNext.Buffers.Binary.Leb128<T>` type for more information
* Added `SlideToEnd` method to `SpanWriter<T>` type
* Added `IsBitSet` and `SetBit` generic methods to `Number` type
* Added `DetachOrCopyBuffer` to `BufferWriterSlim<T>` type

<a href="https://www.nuget.org/packages/dotnext.metaprogramming/5.16.1">DotNext.Metaprogramming 5.16.1</a>
Release Date: 12-29-2024

This release is aimed to improve AOT compatibility. All the examples in the repo are now AOT compatible.
<a href="https://www.nuget.org/packages/dotnext/5.17.0">DotNext 5.17.0</a>
* Fixed AOT compatibility in `TaskType` class
* Added [ISpanFormattable](https://learn.microsoft.com/en-us/dotnet/api/system.ispanformattable) and [IParsable&lt;T&gt;](https://learn.microsoft.com/en-us/dotnet/api/system.iparsable-1) interfaces to `HttpEndPoint`
* Introduced `TryEncodeAsUtf8` extension method for `SpanWriter<T>`
* Added more factory methods to `DotNext.Buffers.Memory` class to create [ReadOnlySequence&lt;T&gt;](https://learn.microsoft.com/en-us/dotnet/api/system.buffers.readonlysequence-1)
* `Intrinsics.KeepAlive` is introduced for value types
* Added `Synchronization.Wait()` synchronous methods for blocking wait of [value tasks](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.valuetask) without wait handles

<a href="https://www.nuget.org/packages/dotnext.metaprogramming/5.17.0">DotNext.Metaprogramming 5.17.0</a>
* Updated dependencies

<a href="https://www.nuget.org/packages/dotnext.unsafe/5.16.1">DotNext.Unsafe 5.16.1</a>
<a href="https://www.nuget.org/packages/dotnext.unsafe/5.17.0">DotNext.Unsafe 5.17.0</a>
* Improved AOT support
* Fixed finalizer for unmanaged memory manager that allows to release the allocated unmanaged memory automatically by GC to avoid memory leak
* Updated dependencies

<a href="https://www.nuget.org/packages/dotnext.threading/5.16.1">DotNext.Threading 5.16.1</a>
* Async locks with synchronous acquisition methods now throw [LockRecursionException](https://learn.microsoft.com/en-us/dotnet/api/system.threading.lockrecursionexception) if the current thread tries to acquire the lock synchronously and recursively.
* Added support of cancellation token to synchronous acquisition methods of `AsyncExclusiveLock` and `AsyncReaderWriterLock` classes
* Introduced `LinkTo` method overload that supports multiple cancellation tokens
<a href="https://www.nuget.org/packages/dotnext.threading/5.17.0">DotNext.Threading 5.17.0</a>
* Improved AOT support

<a href="https://www.nuget.org/packages/dotnext.io/5.16.1">DotNext.IO 5.16.1</a>
* Introduced `RandomAccessStream` class that represents [Stream](https://learn.microsoft.com/en-us/dotnet/api/system.io.stream) wrapper over the underlying data storage that supports random access pattern
* Added extension method for `SpanWriter<byte>` that provides length-prefixed string encoding
<a href="https://www.nuget.org/packages/dotnext.io/5.17.0">DotNext.IO 5.17.0</a>
* Reduced memory consumption for applications that use `FileReader` and `FileWriter` classes. These classes are now implemented by using lazy buffer pattern. It means that the different instances can reuse the same buffer taken from the pool
* Fixed [255](https://github.com/dotnet/dotNext/issues/255)
* `PoolingBufferedStream` is introduced to replace classic [BufferedStream](https://learn.microsoft.com/en-us/dotnet/api/system.io.bufferedstream). This class supports memory pooling and implements lazy buffer pattern

<a href="https://www.nuget.org/packages/dotnext.net.cluster/5.16.1">DotNext.Net.Cluster 5.16.1</a>
* Updated dependencies
<a href="https://www.nuget.org/packages/dotnext.net.cluster/5.17.0">DotNext.Net.Cluster 5.17.0</a>
* Improved AOT support

<a href="https://www.nuget.org/packages/dotnext.aspnetcore.cluster/5.16.1">DotNext.AspNetCore.Cluster 5.16.1</a>
* Updated dependencies
<a href="https://www.nuget.org/packages/dotnext.aspnetcore.cluster/5.17.0">DotNext.AspNetCore.Cluster 5.17.0</a>
* Improved AOT support
* Fixed [254](https://github.com/dotnet/dotNext/issues/254)

<a href="https://www.nuget.org/packages/dotnext.maintenanceservices/0.5.0">DotNext.MaintenanceServices 0.5.0</a>
* Improved AOT support

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

Expand Down
15 changes: 15 additions & 0 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ variables:
Solution: src/DotNext.sln
TestFolder: src/DotNext.Tests
TestProject: $(TestFolder)/DotNext.Tests.csproj
AotTestFolder: src/DotNext.AotTests
AotTestProject: $(AotTestFolder)/DotNext.AotTests.csproj
InternetAccess: false
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
isMain: $[eq(variables['Build.SourceBranch'], 'refs/heads/master')]
Expand Down Expand Up @@ -47,6 +49,19 @@ stages:
feedsToUse: 'config'
nugetConfigPath: 'NuGet.config'
arguments: --configuration Debug
- task: DotNetCoreCLI@2
displayName: Publish AOT Tests
inputs:
command: publish
publishWebProjects: false
zipAfterPublish: false
projects: $(AotTestProject)
arguments: --configuration Release --output $(AotTestFolder)/bin/
- task: CmdLine@2
displayName: Run AOT Tests
inputs:
workingDirectory: $(AotTestFolder)/bin/DotNext.AotTests
script: ./DotNext.AotTests
- task: DotNetCoreCLI@2
displayName: Test Debug
inputs:
Expand Down
6 changes: 6 additions & 0 deletions src/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" />
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageVersion Include="MSTest.Engine" Version="1.0.0-alpha.24562.1" />
<PackageVersion Include="MSTest.SourceGeneration" Version="1.0.0-alpha.24562.1" />
<PackageVersion Include="Microsoft.Testing.Extensions.TrxReport" Version="1.0.2" />
<PackageVersion Include="Microsoft.Testing.Platform.MSBuild" Version="1.5.0" />
<PackageVersion Include="MSTest.TestFramework" Version="3.7.0" />
<PackageVersion Include="MSTest.Analyzers" Version="3.7.0" />
</ItemGroup>
<ItemGroup>
<!--Misc packages-->
Expand Down
24 changes: 24 additions & 0 deletions src/DotNext.AotTests/Collections/Generic/ListTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace DotNext.Collections.Generic;

[TestClass]
public class ListTests
{
[TestMethod]
public void Indexer()
{
IList<long> array = [5L, 6L, 30L];
Assert.AreEqual(30L, List.Indexer<long>.Getter(array, 2));
List.Indexer<long>.Setter(array, 1, 10L);
Assert.AreEqual(10L, array.IndexerGetter().Invoke(1));
array.IndexerSetter().Invoke(0, 6L);
Assert.AreEqual(6L, array.IndexerGetter().Invoke(0));
}

[TestMethod]
public void ReadOnlyIndexer()
{
IReadOnlyList<long> array = [5L, 6L, 20L];
Assert.AreEqual(20L, List.Indexer<long>.ReadOnly(array, 2));
Assert.AreEqual(6L, array.IndexerGetter().Invoke(1));
}
}
35 changes: 35 additions & 0 deletions src/DotNext.AotTests/DotNext.AotTests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>DotNext</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>5.17.0</Version>
<IsPackable>false</IsPackable>
<Authors>.NET Foundation and Contributors</Authors>
<Product>.NEXT Family of Libraries</Product>
<Description>AOT compatibility tests for .NEXT Familiy of Libraries</Description>
<Copyright>Copyright © .NET Foundation and Contributors</Copyright>
<PackageLicenseUrl>https://github.com/dotnet/DotNext/blob/master/LICENSE</PackageLicenseUrl>
<PackageProjectUrl>https://github.com/dotnet/DotNext</PackageProjectUrl>
<RepositoryUrl>https://github.com/dotnet/DotNext.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<InvariantGlobalization>true</InvariantGlobalization>
<PublishAot>true</PublishAot>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\DotNext\DotNext.csproj"/>
<PackageReference Include="MSTest.Engine" />
<PackageReference Include="MSTest.SourceGeneration" />
<PackageReference Include="Microsoft.Testing.Extensions.TrxReport" />
<PackageReference Include="Microsoft.Testing.Platform.MSBuild"/>
<PackageReference Include="MSTest.TestFramework" />
<PackageReference Include="MSTest.Analyzers" />
</ItemGroup>

<ItemGroup>
<Using Include="Microsoft.VisualStudio.TestTools.UnitTesting" />
</ItemGroup>
</Project>
23 changes: 23 additions & 0 deletions src/DotNext.AotTests/Reflection/TaskTypeTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace DotNext.Reflection;

[TestClass]
public class TaskTypeTests
{
[TestMethod]
public void IsCompletedSuccessfullyPropertyGetter()
{
Assert.IsTrue(TaskType.IsCompletedSuccessfullyGetter(Task.CompletedTask));
}

[TestMethod]
public void GetResultSynchronously()
{
Assert.AreEqual(42, TaskType.GetResultGetter<int>().Invoke(Task.FromResult(42)));
}

[TestMethod]
public void IsCompletedPropertyGetter()
{
Assert.IsTrue(Task.CompletedTask.GetIsCompletedGetter().Invoke());
}
}
2 changes: 1 addition & 1 deletion src/DotNext.Benchmarks/DotNext.Benchmarks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<RootNamespace>DotNext</RootNamespace>
<StartupObject>DotNext.Program</StartupObject>
<IsPackable>false</IsPackable>
<Version>5.16.1</Version>
<Version>5.17.0</Version>
<Authors>.NET Foundation and Contributors</Authors>
<Product>.NEXT Family of Libraries</Product>
<Description>Various benchmarks demonstrating performance aspects of .NEXT extensions</Description>
Expand Down
19 changes: 19 additions & 0 deletions src/DotNext.IO/Buffers/IBufferedChannel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System.Buffers;

namespace DotNext.Buffers;

/// <summary>
/// Represents buffered reader or writer.
/// </summary>
public interface IBufferedChannel : IResettable, IDisposable
{
/// <summary>
/// Gets buffer allocator.
/// </summary>
MemoryAllocator<byte>? Allocator { get; init; }

/// <summary>
/// Gets the maximum size of the internal buffer.
/// </summary>
int MaxBufferSize { get; init; }
}
55 changes: 55 additions & 0 deletions src/DotNext.IO/Buffers/IBufferedReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
namespace DotNext.Buffers;

/// <summary>
/// Represents buffered reader.
/// </summary>
public interface IBufferedReader : IBufferedChannel
{
/// <summary>
/// Gets unconsumed part of the buffer.
/// </summary>
ReadOnlyMemory<byte> Buffer { get; }

/// <summary>
/// Advances read position.
/// </summary>
/// <param name="count">The number of consumed bytes.</param>
/// <exception cref="ObjectDisposedException">The reader has been disposed.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="count"/> is larger than the length of <see cref="Buffer"/>.</exception>
void Consume(int count);

/// <summary>
/// Fetches the data from the underlying storage to the internal buffer.
/// </summary>
/// <param name="token">The token that can be used to cancel the operation.</param>
/// <returns>
/// <see langword="true"/> if the data has been copied from the underlying storage to the internal buffer;
/// <see langword="false"/> if no more data to read.
/// </returns>
/// <exception cref="ObjectDisposedException">The reader has been disposed.</exception>
/// <exception cref="InternalBufferOverflowException">Internal buffer has no free space.</exception>
/// <exception cref="OperationCanceledException">The operation has been canceled.</exception>
ValueTask<bool> ReadAsync(CancellationToken token = default);

/// <summary>
/// Reads the block of the memory.
/// </summary>
/// <param name="destination">The output buffer.</param>
/// <param name="token">The token that can be used to cancel the operation.</param>
/// <returns>The number of bytes copied to <paramref name="destination"/>.</returns>
/// <exception cref="ObjectDisposedException">The reader has been disposed.</exception>
/// <exception cref="OperationCanceledException">The operation has been canceled.</exception>
async ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken token = default)
{
var result = 0;
for (int bytesRead; result < destination.Length; result += bytesRead, destination = destination.Slice(bytesRead))
{
Buffer.Span.CopyTo(destination.Span, out bytesRead);
Consume(bytesRead);
if (!await ReadAsync(token).ConfigureAwait(false))
break;
}

return result;
}
}
73 changes: 73 additions & 0 deletions src/DotNext.IO/Buffers/IBufferedWriter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using System.Buffers;

namespace DotNext.Buffers;

/// <summary>
/// Represents buffered writer.
/// </summary>
public interface IBufferedWriter : IBufferedChannel, IBufferWriter<byte>
{
/// <summary>
/// Marks the specified number of bytes in the buffer as produced.
/// </summary>
/// <param name="count">The number of produced bytes.</param>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="count"/> is larger than the length of <see cref="Buffer"/>.</exception>
/// <exception cref="ObjectDisposedException">The writer has been disposed.</exception>
void Produce(int count);

/// <summary>
/// The remaining part of the internal buffer available for write.
/// </summary>
/// <remarks>
/// The size of returned buffer may be less than or equal to <see cref="IBufferedChannel.MaxBufferSize"/>.
/// </remarks>
Memory<byte> Buffer { get; }

/// <summary>
/// Flushes buffered data to the underlying storage.
/// </summary>
/// <param name="token">The token that can be used to cancel the operation.</param>
/// <returns>The task representing asynchronous result.</returns>
/// <exception cref="ObjectDisposedException">The writer has been disposed.</exception>
/// <exception cref="OperationCanceledException">The operation has been canceled.</exception>
ValueTask WriteAsync(CancellationToken token = default);

/// <summary>
/// Writes the data to the underlying storage through the buffer.
/// </summary>
/// <param name="input">The input data to write.</param>
/// <param name="token">The token that can be used to cancel the operation.</param>
/// <returns>The task representing asynchronous result.</returns>
/// <exception cref="ObjectDisposedException">The object has been disposed.</exception>
/// <exception cref="OperationCanceledException">The operation has been canceled.</exception>
async ValueTask WriteAsync(ReadOnlyMemory<byte> input, CancellationToken token = default)
{
for (int bytesWritten; !input.IsEmpty; input = input.Slice(bytesWritten))
{
input.Span.CopyTo(Buffer.Span, out bytesWritten);
Produce(bytesWritten);
await WriteAsync(token).ConfigureAwait(false);
}
}

/// <inheritdoc />
void IBufferWriter<byte>.Advance(int count) => Produce(count);

/// <inheritdoc />
Memory<byte> IBufferWriter<byte>.GetMemory(int sizeHint)
{
ArgumentOutOfRangeException.ThrowIfNegative(sizeHint);

var result = Buffer;
return sizeHint <= result.Length ? result : throw new InsufficientMemoryException();
}

/// <inheritdoc />
Span<byte> IBufferWriter<byte>.GetSpan(int sizeHint)
{
ArgumentOutOfRangeException.ThrowIfNegative(sizeHint);

var result = Buffer.Span;
return sizeHint <= result.Length ? result : throw new InsufficientMemoryException();
}
}
Loading

0 comments on commit 09613ee

Please sign in to comment.