Skip to content

Commit

Permalink
Release 5.16.1
Browse files Browse the repository at this point in the history
  • Loading branch information
sakno committed Dec 7, 2024
1 parent eaf9902 commit 2d385ec
Show file tree
Hide file tree
Showing 27 changed files with 141 additions and 57 deletions.
16 changes: 8 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
Release Notes
====

# 12-05-2024
<a href="https://www.nuget.org/packages/dotnext/5.16.0">DotNext 5.16.0</a>
# 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.0">DotNext.Metaprogramming 5.16.0</a>
<a href="https://www.nuget.org/packages/dotnext.metaprogramming/5.16.1">DotNext.Metaprogramming 5.16.1</a>
* Updated dependencies

<a href="https://www.nuget.org/packages/dotnext.unsafe/5.16.0">DotNext.Unsafe 5.16.0</a>
<a href="https://www.nuget.org/packages/dotnext.unsafe/5.16.1">DotNext.Unsafe 5.16.1</a>
* Updated dependencies

<a href="https://www.nuget.org/packages/dotnext.threading/5.16.0">DotNext.Threading 5.16.0</a>
<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.io/5.16.0">DotNext.IO 5.16.0</a>
<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.net.cluster/5.16.0">DotNext.Net.Cluster 5.16.0</a>
<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.aspnetcore.cluster/5.16.0">DotNext.AspNetCore.Cluster 5.16.0</a>
<a href="https://www.nuget.org/packages/dotnext.aspnetcore.cluster/5.16.1">DotNext.AspNetCore.Cluster 5.16.1</a>
* Updated dependencies

# 10-16-2024
Expand Down
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,33 +44,33 @@ 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-05-2024
Release Date: 12-07-2024

<a href="https://www.nuget.org/packages/dotnext/5.16.0">DotNext 5.16.0</a>
<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.0">DotNext.Metaprogramming 5.16.0</a>
<a href="https://www.nuget.org/packages/dotnext.metaprogramming/5.16.1">DotNext.Metaprogramming 5.16.1</a>
* Updated dependencies

<a href="https://www.nuget.org/packages/dotnext.unsafe/5.16.0">DotNext.Unsafe 5.16.0</a>
<a href="https://www.nuget.org/packages/dotnext.unsafe/5.16.1">DotNext.Unsafe 5.16.1</a>
* Updated dependencies

<a href="https://www.nuget.org/packages/dotnext.threading/5.16.0">DotNext.Threading 5.16.0</a>
<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.io/5.16.0">DotNext.IO 5.16.0</a>
<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.net.cluster/5.16.0">DotNext.Net.Cluster 5.16.0</a>
<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.aspnetcore.cluster/5.16.0">DotNext.AspNetCore.Cluster 5.16.0</a>
<a href="https://www.nuget.org/packages/dotnext.aspnetcore.cluster/5.16.1">DotNext.AspNetCore.Cluster 5.16.1</a>
* Updated dependencies

Changelog for previous versions located [here](./CHANGELOG.md).
Expand Down
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.0</Version>
<Version>5.16.1</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/Binary/SevenBitEncodedIntReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace DotNext.Buffers.Binary;

[StructLayout(LayoutKind.Auto)]
internal struct SevenBitEncodedIntReader() : IBufferReader, ISupplier<int>
{
private Leb128<uint> decoder;
private bool incompleted = true;

readonly int IBufferReader.RemainingBytes => Unsafe.BitCast<bool, byte>(incompleted);

void IReadOnlySpanConsumer<byte>.Invoke(ReadOnlySpan<byte> source)
=> incompleted = decoder.Append(MemoryMarshal.GetReference(source));

readonly int ISupplier<int>.Invoke() => (int)decoder.Value;
}
8 changes: 5 additions & 3 deletions src/DotNext.IO/Buffers/BufferWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,17 @@ static void WriteSlow(IBufferWriter<T> writer, in ReadOnlySequence<T> value)

internal static unsafe int WriteLength(this ref SpanWriter<byte> destination, int value, LengthFormat lengthFormat)
{
delegate*<ref SpanWriter<byte>, int, int> writer = lengthFormat switch
Debug.Assert(value >= 0);

delegate*<ref SpanWriter<byte>, uint, int> writer = lengthFormat switch
{
LengthFormat.LittleEndian => &ByteBuffer.WriteLittleEndian,
LengthFormat.BigEndian => &ByteBuffer.WriteBigEndian,
LengthFormat.Compressed => &ByteBuffer.WriteLeb128<int>,
LengthFormat.Compressed => &ByteBuffer.WriteLeb128<uint>,
_ => throw new ArgumentOutOfRangeException(nameof(lengthFormat)),
};

return writer(ref destination, value);
return writer(ref destination, (uint)value);
}

internal static int WriteLength(this IBufferWriter<byte> buffer, int length, LengthFormat lengthFormat)
Expand Down
2 changes: 1 addition & 1 deletion src/DotNext.IO/DotNext.IO.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<Authors>.NET Foundation and Contributors</Authors>
<Company />
<Product>.NEXT Family of Libraries</Product>
<VersionPrefix>5.16.0</VersionPrefix>
<VersionPrefix>5.16.1</VersionPrefix>
<VersionSuffix></VersionSuffix>
<AssemblyName>DotNext.IO</AssemblyName>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
Expand Down
2 changes: 1 addition & 1 deletion src/DotNext.IO/IO/FileReader.Binary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ ValueTask<TReader> IAsyncBinaryReader.ReadAsync<TReader>(TReader reader, Cancell
{
LengthFormat.LittleEndian => ReadLittleEndianAsync<int>(token),
LengthFormat.BigEndian => ReadBigEndianAsync<int>(token),
LengthFormat.Compressed => ReadAsync<int, Leb128Reader<int>>(new(), token),
LengthFormat.Compressed => ReadAsync<int, SevenBitEncodedIntReader>(new(), token),
_ => ValueTask.FromException<int>(new ArgumentOutOfRangeException(nameof(lengthFormat))),
};

Expand Down
2 changes: 1 addition & 1 deletion src/DotNext.IO/IO/IAsyncBinaryReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ private async ValueTask<TResult> ReadAsync<TResult, TReader>(TReader reader, Can
{
LengthFormat.LittleEndian => ReadLittleEndianAsync<int>(token),
LengthFormat.BigEndian => ReadBigEndianAsync<int>(token),
LengthFormat.Compressed => ReadAsync<int, Leb128Reader<int>>(new(), token),
LengthFormat.Compressed => ReadAsync<int, SevenBitEncodedIntReader>(new(), token),
_ => ValueTask.FromException<int>(new ArgumentOutOfRangeException(nameof(lengthFormat))),
};

Expand Down
2 changes: 1 addition & 1 deletion src/DotNext.IO/IO/Pipelines/PipeExtensions.Readers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public static ValueTask<T> ReadBigEndianAsync<T>(this PipeReader reader, Cancell
{
LengthFormat.LittleEndian => reader.ReadLittleEndianAsync<int>(token),
LengthFormat.BigEndian => reader.ReadBigEndianAsync<int>(token),
LengthFormat.Compressed => ReadAsync<int, Leb128Reader<int>>(reader, new(), token),
LengthFormat.Compressed => ReadAsync<int, SevenBitEncodedIntReader>(reader, new(), token),
_ => ValueTask.FromException<int>(new ArgumentOutOfRangeException(nameof(lengthFormat))),
};

Expand Down
4 changes: 2 additions & 2 deletions src/DotNext.IO/IO/SequenceReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,8 @@ public MemoryOwner<byte> ReadBlock(LengthFormat lengthFormat, MemoryAllocator<by

private int Read7BitEncodedInt32()
{
var parser = new Leb128Reader<int>();
return Read<int, Leb128Reader<int>>(ref parser);
var parser = new SevenBitEncodedIntReader();
return Read<int, SevenBitEncodedIntReader>(ref parser);
}

private int ReadLength(LengthFormat lengthFormat) => lengthFormat switch
Expand Down
2 changes: 1 addition & 1 deletion src/DotNext.IO/IO/StreamExtensions.Readers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ private static unsafe ValueTask<int> ReadLengthAsync(this Stream stream, LengthF
return reader(stream, buffer, token);

static ValueTask<int> Read7BitEncodedIntAsync(Stream stream, Memory<byte> buffer, CancellationToken token)
=> ReadAsync<int, Leb128Reader<int>>(stream, new(), buffer, token);
=> ReadAsync<int, SevenBitEncodedIntReader>(stream, new(), buffer, token);
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion src/DotNext.Metaprogramming/DotNext.Metaprogramming.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<ImplicitUsings>true</ImplicitUsings>
<IsTrimmable>false</IsTrimmable>
<Features>nullablePublicOnly</Features>
<VersionPrefix>5.16.0</VersionPrefix>
<VersionPrefix>5.16.1</VersionPrefix>
<VersionSuffix></VersionSuffix>
<Authors>.NET Foundation</Authors>
<Product>.NEXT Family of Libraries</Product>
Expand Down
47 changes: 47 additions & 0 deletions src/DotNext.Tests/Buffers/Binary/Leb128Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace DotNext.Buffers.Binary;

using static IO.StreamSource;

public sealed class Leb128Tests : Test
{
private static void EncodeDecode<T>(ReadOnlySpan<T> values)
Expand Down Expand Up @@ -36,4 +38,49 @@ public static void EncodeDecodeEmptyBuffer()
False(Leb128<int>.TryGetBytes(42, Span<byte>.Empty, out _));
False(Leb128<short>.TryParse(ReadOnlySpan<byte>.Empty, out _, out _));
}

[Theory]
[InlineData(0)]
[InlineData(100500)]
[InlineData(int.MaxValue)]
[InlineData(0x80)]
[InlineData(0x40)]
[InlineData(0x7F)]
public static void CompatibilityWithBinaryReader(int expected)
{
var buffer = new byte[Leb128<int>.MaxSizeInBytes];
using var reader = new BinaryReader(new ReadOnlyMemory<byte>(buffer).AsStream());
True(Leb128<uint>.TryGetBytes((uint)expected, buffer, out _));
Equal(expected, reader.Read7BitEncodedInt());
}

[Theory]
[InlineData(0)]
[InlineData(100500)]
[InlineData(int.MaxValue)]
[InlineData(0x80)]
[InlineData(0x40)]
[InlineData(0x7F)]
public static void CompatibilityWithBinaryWriter(int expected)
{
using var stream = new MemoryStream(Leb128<int>.MaxSizeInBytes);
using var writer = new BinaryWriter(stream);
writer.Write7BitEncodedInt(expected);

True(Leb128<uint>.TryParse(stream.GetBuffer(), out var actual, out _));
Equal((uint)expected, actual);
}

[Fact]
public static void DifferenceBetweenSignedAndUnsignedEncoding()
{
Equal(Leb128<int>.MaxSizeInBytes, Leb128<uint>.MaxSizeInBytes);

Span<byte> buffer = stackalloc byte[Leb128<int>.MaxSizeInBytes];
True(Leb128<uint>.TryGetBytes(0x7Fu, buffer, out var bytesWritten));
Equal(1, bytesWritten);

True(Leb128<int>.TryGetBytes(0x7F, buffer, out bytesWritten));
Equal(2, bytesWritten);
}
}
4 changes: 2 additions & 2 deletions src/DotNext.Tests/Buffers/BufferWriterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ public static void Rendering()
[InlineData(124)]
public static void WriteStringBuilder(int stringLength)
{
var str = Random.Shared.NextString("abcdefghijklmnopqrstuvwxyz", stringLength);
var str = Random.Shared.NextString(Alphabet, stringLength);

var builder = new StringBuilder();
for (var i = 0; i < 3; i++)
Expand All @@ -364,7 +364,7 @@ public static void WriteStringBuilder(int stringLength)
[InlineData(124)]
public static void WriteStringBuilder2(int stringLength)
{
var str = Random.Shared.NextString("abcdefghijklmnopqrstuvwxyz", stringLength);
var str = Random.Shared.NextString(Alphabet, stringLength);

var builder = new StringBuilder();
for (var i = 0; i < 3; i++)
Expand Down
2 changes: 1 addition & 1 deletion src/DotNext.Tests/Buffers/ChunkSequenceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public static void CopyFromSequence()
[InlineData(124)]
public static void StringBuilderToSequence(int stringLength)
{
var str = Random.Shared.NextString("abcdefghijklmnopqrstuvwxyz", stringLength);
var str = Random.Shared.NextString(Alphabet, stringLength);

var builder = new StringBuilder();
for (var i = 0; i < 3; i++)
Expand Down
2 changes: 1 addition & 1 deletion src/DotNext.Tests/Buffers/SpanReaderWriterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ public static void Rendering()
[InlineData(124)]
public static void WriteStringBuilder(int stringLength)
{
var str = Random.Shared.NextString("abcdefghijklmnopqrstuvwxyz", stringLength);
var str = Random.Shared.NextString(Alphabet, stringLength);

var builder = new StringBuilder();
for (var i = 0; i < 3; i++)
Expand Down
2 changes: 1 addition & 1 deletion src/DotNext.Tests/DotNext.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<LangVersion>latest</LangVersion>
<ImplicitUsings>true</ImplicitUsings>
<EnableNETAnalyzers>false</EnableNETAnalyzers>
<Version>5.16.0</Version>
<Version>5.16.1</Version>
<IsPackable>false</IsPackable>
<Authors>.NET Foundation and Contributors</Authors>
<Product>.NEXT Family of Libraries</Product>
Expand Down
28 changes: 19 additions & 9 deletions src/DotNext.Tests/IO/StreamExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,28 +101,38 @@ public static async Task ReadWriteBlittableTypeAsync()
Equal(10M, (await ms.ReadAsync<Blittable<decimal>>(buffer)).Value);
}

[Fact]
public static async Task BinaryReaderInterop()
[Theory]
[InlineData(7)]
[InlineData(16)]
[InlineData(0x7F)]
[InlineData(0x80)]
public static async Task BinaryReaderInterop(int length)
{
var expected = Random.Shared.NextString(Alphabet + AlphabetUpperCase + Numbers, length);
using var ms = new MemoryStream();
await ms.EncodeAsync("ABC".AsMemory(), Encoding.UTF8, LengthFormat.Compressed, new byte[16]);
await ms.EncodeAsync(expected.AsMemory(), Encoding.UTF8, LengthFormat.Compressed, new byte[16]);
ms.Position = 0;
using var reader = new BinaryReader(ms, Encoding.UTF8, true);
Equal("ABC", reader.ReadString());
Equal(expected, reader.ReadString());
}

[Fact]
public static async Task BinaryWriterInterop()
[Theory]
[InlineData(7)]
[InlineData(16)]
[InlineData(0x7F)]
[InlineData(0x80)]
public static async Task BinaryWriterInterop(int length)
{
var expected = Random.Shared.NextString(Alphabet + AlphabetUpperCase + Numbers, length);
using var ms = new MemoryStream();
using (var writer = new BinaryWriter(ms, Encoding.UTF8, true))
await using (var writer = new BinaryWriter(ms, Encoding.UTF8, true))
{
writer.Write("ABC");
writer.Write(expected);
}
ms.Position = 0;

using var result = await ms.DecodeAsync(Encoding.UTF8, LengthFormat.Compressed, new byte[16]);
Equal("ABC", result.ToString());
Equal(expected, result.Span);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ internal LocalMember(bool smallAmountOfMetadata = false)
metadata.Add("a", "b");
else
{
const string AllowedChars = "abcdefghijklmnopqrstuvwxyz1234567890";
const string allowedChars = Alphabet + Numbers;
for (var i = 0; i < 20; i++)
metadata.Add(string.Concat("key", i.ToString()), Random.Shared.NextString(AllowedChars, 20));
metadata.Add(string.Concat("key", i.ToString()), Random.Shared.NextString(allowedChars, 20));
}
Metadata = metadata.ToImmutableDictionary();
}
Expand Down
4 changes: 4 additions & 0 deletions src/DotNext.Tests/Test.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ namespace DotNext;
[ExcludeFromCodeCoverage]
public abstract class Test : Assert
{
protected const string Alphabet = "abcdefghijklmnopqrstuvwxyz";
protected const string AlphabetUpperCase = "ABCDEFGHIJKLMNOPQRSTUVWXY";
protected const string Numbers = "0123456789";

private protected static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(20);

private protected static byte[] RandomBytes(int size)
Expand Down
2 changes: 1 addition & 1 deletion src/DotNext.Threading/DotNext.Threading.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<ImplicitUsings>true</ImplicitUsings>
<IsTrimmable>true</IsTrimmable>
<Features>nullablePublicOnly</Features>
<VersionPrefix>5.16.0</VersionPrefix>
<VersionPrefix>5.16.1</VersionPrefix>
<VersionSuffix></VersionSuffix>
<Authors>.NET Foundation and Contributors</Authors>
<Product>.NEXT Family of Libraries</Product>
Expand Down
2 changes: 1 addition & 1 deletion src/DotNext.Unsafe/DotNext.Unsafe.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<IsTrimmable>true</IsTrimmable>
<VersionPrefix>5.16.0</VersionPrefix>
<VersionPrefix>5.16.1</VersionPrefix>
<Features>nullablePublicOnly</Features>
<VersionSuffix></VersionSuffix>
<Authors>.NET Foundation and Contributors</Authors>
Expand Down
Loading

0 comments on commit 2d385ec

Please sign in to comment.