Skip to content

Commit

Permalink
Release 5.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
sakno committed Feb 28, 2024
1 parent a0427a7 commit 3e6ff7c
Show file tree
Hide file tree
Showing 25 changed files with 591 additions and 75 deletions.
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,30 @@
Release Notes
====

# 02-28-2024
<a href="https://www.nuget.org/packages/dotnext/5.1.0">DotNext 5.1.0</a>
* Added `Span.Advance<T>` extension method for spans
* `CollectionType.GetItemType` now correctly recognizes enumerable pattern even if target type doesn't implement `IEnumerable<T>`

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

<a href="https://www.nuget.org/packages/dotnext.unsafe/5.1.0">DotNext.Unsafe 5.1.0</a>
* Added `UnmanagedMemory.AsMemory` static method that allows to wrap unmanaged pointer into [Memory&lt;T&gt;](https://learn.microsoft.com/en-us/dotnet/api/system.memory-1)

<a href="https://www.nuget.org/packages/dotnext.threading/5.1.0">DotNext.Threading 5.1.0</a>
* Updated dependencies

<a href="https://www.nuget.org/packages/dotnext.io/5.1.0">DotNext.IO 5.1.0</a>
* Merged [225](https://github.com/dotnet/dotNext/pull/225)
* Added `AsUnbufferedStream` extension method for [SafeFileHandle](https://learn.microsoft.com/en-us/dotnet/api/microsoft.win32.safehandles.safefilehandle) class

<a href="https://www.nuget.org/packages/dotnext.net.cluster/5.1.0">DotNext.Net.Cluster 5.1.0</a>
* Updated dependencies

<a href="https://www.nuget.org/packages/dotnext.aspnetcore.cluster/5.1.0">DotNext.AspNetCore.Cluster 5.1.0</a>
* Updated dependencies

# 02-25-2024
<a href="https://www.nuget.org/packages/dotnext/5.0.3">DotNext 5.0.3</a>
* Fixed behavior to no-op when `GCLatencyModeScope` is initialized to default
Expand Down
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ contact [[email protected]](mailto:[email protected]) with
## Branching Model
This repository uses branching model known as [git flow](https://nvie.com/posts/a-successful-git-branching-model/). Use **develop** as the destination branch in your Pull Request.

Since 5.x release, squash commit is used to merge all commits related to the release when moving to `main` branch.

## Backward Compatibility
Contributions must not contain breaking changes such as backward incompatible modification of API signatures. The only exception is a new major version of the library. However, it should pass through code review and discussion.

Expand Down
28 changes: 15 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,28 +44,30 @@ 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: 02-25-2024
Release Date: 02-28-2024

<a href="https://www.nuget.org/packages/dotnext/5.0.3">DotNext 5.0.3</a>
* Fixed behavior to no-op when `GCLatencyModeScope` is initialized to default
<a href="https://www.nuget.org/packages/dotnext/5.1.0">DotNext 5.1.0</a>
* Added `Span.Advance<T>` extension method for spans
* `CollectionType.GetItemType` now correctly recognizes enumerable pattern even if target type doesn't implement `IEnumerable<T>`

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

<a href="https://www.nuget.org/packages/dotnext.unsafe/5.0.3">DotNext.Unsafe 5.0.3</a>
* Updated dependencies
<a href="https://www.nuget.org/packages/dotnext.unsafe/5.1.0">DotNext.Unsafe 5.1.0</a>
* Added `UnmanagedMemory.AsMemory` static method that allows to wrap unmanaged pointer into [Memory&lt;T&gt;](https://learn.microsoft.com/en-us/dotnet/api/system.memory-1)

<a href="https://www.nuget.org/packages/dotnext.threading/5.0.3">DotNext.Threading 5.0.3</a>
<a href="https://www.nuget.org/packages/dotnext.threading/5.1.0">DotNext.Threading 5.1.0</a>
* Updated dependencies

<a href="https://www.nuget.org/packages/dotnext.io/5.0.3">DotNext.IO 5.0.3</a>
* Updated dependencies
<a href="https://www.nuget.org/packages/dotnext.io/5.1.0">DotNext.IO 5.1.0</a>
* Merged [225](https://github.com/dotnet/dotNext/pull/225)
* Added `AsUnbufferedStream` extension method for [SafeFileHandle](https://learn.microsoft.com/en-us/dotnet/api/microsoft.win32.safehandles.safefilehandle) class

<a href="https://www.nuget.org/packages/dotnext.net.cluster/5.0.3">DotNext.Net.Cluster 5.0.3</a>
* Attempt to fix [221](https://github.com/dotnet/dotNext/issues/221)
<a href="https://www.nuget.org/packages/dotnext.net.cluster/5.1.0">DotNext.Net.Cluster 5.1.0</a>
* Updated dependencies

<a href="https://www.nuget.org/packages/dotnext.aspnetcore.cluster/5.0.3">DotNext.AspNetCore.Cluster 5.0.3</a>
* Attempt to fix [221](https://github.com/dotnet/dotNext/issues/221)
<a href="https://www.nuget.org/packages/dotnext.aspnetcore.cluster/5.1.0">DotNext.AspNetCore.Cluster 5.1.0</a>
* Updated dependencies

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

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.0.3</VersionPrefix>
<VersionPrefix>5.1.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
<AssemblyName>DotNext.IO</AssemblyName>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
Expand Down
2 changes: 2 additions & 0 deletions src/DotNext.IO/ExceptionMessages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,6 @@ internal static string DirectoryNotFound(string path)
internal static string WriterInReadMode => (string)Resources.Get();

internal static string NoConsumerProvided => (string)Resources.Get();

internal static string FileHandleClosed => (string)Resources.Get();
}
3 changes: 2 additions & 1 deletion src/DotNext.IO/ExceptionMessages.restext
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ StreamNotWritable=Stream is not writable
StreamNotReadable=Stream is not readable
DirectoryNotFound=Directory {0} doesn't exist
WriterInReadMode=The writer is in read-only mode. Dispose active memory manager obtained from writer
NoConsumerProvided=No actual consumer is provided
NoConsumerProvided=No actual consumer is provided
FileHandleClosed=The file handle is closed
21 changes: 21 additions & 0 deletions src/DotNext.IO/IO/StreamExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Runtime.CompilerServices;
using Microsoft.Win32.SafeHandles;

namespace DotNext.IO;

Expand All @@ -25,4 +26,24 @@ internal static void ThrowIfEmpty<T>(in Memory<T> buffer, [CallerArgumentExpress
/// <returns>An object that represents multiple streams as one logical stream.</returns>
public static Stream Combine(this Stream stream, ReadOnlySpan<Stream> others)
=> others is { Length: > 0 } ? new SparseStream([stream, .. others]) : stream;

/// <summary>
/// Creates a stream for the specified file handle.
/// </summary>
/// <remarks>
/// The returned stream doesn't own the handle.
/// </remarks>
/// <param name="handle">The file handle.</param>
/// <param name="access">Desired access to the file via stream.</param>
/// <returns>The unbuffered file stream.</returns>
/// <exception cref="ArgumentNullException"><paramref name="handle"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentException"><paramref name="handle"/> is closed or invalid.</exception>
public static Stream AsUnbufferedStream(this SafeFileHandle handle, FileAccess access)
{
ArgumentNullException.ThrowIfNull(handle);

return handle is { IsInvalid: false, IsClosed: false }
? new UnbufferedFileStream(handle, access)
: throw new ArgumentException(ExceptionMessages.FileHandleClosed, nameof(handle));
}
}
73 changes: 30 additions & 43 deletions src/DotNext.IO/IO/StreamSegment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,16 @@
/// <remarks>
/// The segmentation is supported only for seekable streams.
/// </remarks>
public sealed class StreamSegment : Stream, IFlushable
/// <param name="stream">The underlying stream represented by the segment.</param>
/// <param name="leaveOpen"><see langword="true"/> to leave <paramref name="stream"/> open after the object is disposed; otherwise, <see langword="false"/>.</param>
public sealed class StreamSegment(Stream stream, bool leaveOpen = true) : Stream, IFlushable
{
private readonly bool leaveOpen;
private long length, offset;

/// <summary>
/// Initializes a new segment of the specified stream.
/// </summary>
/// <param name="stream">The underlying stream represented by the segment.</param>
/// <param name="leaveOpen"><see langword="true"/> to leave <paramref name="stream"/> open after the object is disposed; otherwise, <see langword="false"/>.</param>
/// <exception cref="ArgumentNullException"><paramref name="stream"/> is <see langword="null"/>.</exception>
public StreamSegment(Stream stream, bool leaveOpen = true)
{
BaseStream = stream ?? throw new ArgumentNullException(nameof(stream));
length = stream.Length;
offset = 0L;
this.leaveOpen = leaveOpen;
}
private long length = stream.Length, offset;

/// <summary>
/// Gets underlying stream.
/// </summary>
public Stream BaseStream { get; }
public Stream BaseStream => stream;

/// <summary>
/// Establishes segment bounds.
Expand All @@ -40,28 +27,28 @@ public StreamSegment(Stream stream, bool leaveOpen = true)
/// </remarks>
/// <param name="offset">The offset in the underlying stream.</param>
/// <param name="length">The length of the segment.</param>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="length"/> is larger than the reamining length of the underlying stream; or <paramref name="offset"/> if greater than the length of the underlying stream.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="length"/> is larger than the remaining length of the underlying stream; or <paramref name="offset"/> if greater than the length of the underlying stream.</exception>
public void Adjust(long offset, long length)
{
ArgumentOutOfRangeException.ThrowIfGreaterThan((ulong)offset, (ulong)BaseStream.Length, nameof(offset));
ArgumentOutOfRangeException.ThrowIfGreaterThan((ulong)offset, (ulong)(BaseStream.Length - offset), nameof(length));
ArgumentOutOfRangeException.ThrowIfGreaterThan((ulong)offset, (ulong)stream.Length, nameof(offset));
ArgumentOutOfRangeException.ThrowIfGreaterThan((ulong)length, (ulong)(stream.Length - offset), nameof(length));

this.length = length;
this.offset = offset;
BaseStream.Position = offset;
stream.Position = offset;
}

/// <summary>
/// Gets a value indicating whether the current stream supports reading.
/// </summary>
/// <value><see langword="true"/> if the stream supports reading; otherwise, <see langword="false"/>.</value>
public override bool CanRead => BaseStream.CanRead;
public override bool CanRead => stream.CanRead;

/// <summary>
/// Gets a value indicating whether the current stream supports seeking.
/// </summary>
/// <value><see langword="true"/> if the stream supports seeking; otherwise, <see langword="false"/>.</value>
public override bool CanSeek => BaseStream.CanSeek;
public override bool CanSeek => stream.CanSeek;

/// <summary>
/// Gets a value indicating whether the current stream supports writing.
Expand All @@ -75,29 +62,29 @@ public void Adjust(long offset, long length)
/// <inheritdoc/>
public override long Position
{
get => BaseStream.Position - offset;
get => stream.Position - offset;
set
{
ArgumentOutOfRangeException.ThrowIfGreaterThan((ulong)value, (ulong)length, nameof(value));

BaseStream.Position = offset + value;
stream.Position = offset + value;
}
}

private long RemainingBytes => length - Position;

/// <inheritdoc/>
public override void Flush() => BaseStream.Flush();
public override void Flush() => stream.Flush();

/// <inheritdoc/>
public override Task FlushAsync(CancellationToken token = default) => BaseStream.FlushAsync(token);
public override Task FlushAsync(CancellationToken token = default) => stream.FlushAsync(token);

/// <inheritdoc/>
public override bool CanTimeout => BaseStream.CanTimeout;
public override bool CanTimeout => stream.CanTimeout;

/// <inheritdoc/>
public override int ReadByte()
=> Position < length ? BaseStream.ReadByte() : -1;
=> Position < length ? stream.ReadByte() : -1;

/// <inheritdoc/>
public override void WriteByte(byte value) => throw new NotSupportedException();
Expand All @@ -107,30 +94,30 @@ public override int Read(byte[] buffer, int offset, int count)
{
ValidateBufferArguments(buffer, offset, count);

return BaseStream.Read(buffer, offset, (int)Math.Min(count, RemainingBytes));
return stream.Read(buffer, offset, (int)Math.Min(count, RemainingBytes));
}

/// <inheritdoc/>
public override int Read(Span<byte> buffer)
=> BaseStream.Read(buffer.TrimLength(int.CreateSaturating(RemainingBytes)));
=> stream.Read(buffer.TrimLength(int.CreateSaturating(RemainingBytes)));

/// <inheritdoc/>
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state)
{
count = (int)Math.Min(count, RemainingBytes);
return BaseStream.BeginRead(buffer, offset, count, callback, state);
return stream.BeginRead(buffer, offset, count, callback, state);
}

/// <inheritdoc/>
public override int EndRead(IAsyncResult asyncResult) => BaseStream.EndRead(asyncResult);
public override int EndRead(IAsyncResult asyncResult) => stream.EndRead(asyncResult);

/// <inheritdoc/>
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken token = default)
=> BaseStream.ReadAsync(buffer, offset, (int)Math.Min(count, RemainingBytes), token);
=> stream.ReadAsync(buffer, offset, (int)Math.Min(count, RemainingBytes), token);

/// <inheritdoc/>
public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken token = default)
=> BaseStream.ReadAsync(buffer.TrimLength(int.CreateSaturating(RemainingBytes)), token);
=> stream.ReadAsync(buffer.TrimLength(int.CreateSaturating(RemainingBytes)), token);

/// <inheritdoc/>
public override long Seek(long offset, SeekOrigin origin)
Expand All @@ -155,7 +142,7 @@ public override long Seek(long offset, SeekOrigin origin)
/// <inheritdoc/>
public override void SetLength(long value)
{
ArgumentOutOfRangeException.ThrowIfGreaterThan((ulong)value, (ulong)(BaseStream.Length - BaseStream.Position), nameof(value));
ArgumentOutOfRangeException.ThrowIfGreaterThan((ulong)value, (ulong)(stream.Length - stream.Position), nameof(value));

length = value;
}
Expand Down Expand Up @@ -183,30 +170,30 @@ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, As
/// <inheritdoc/>
public override int ReadTimeout
{
get => BaseStream.ReadTimeout;
set => BaseStream.ReadTimeout = value;
get => stream.ReadTimeout;
set => stream.ReadTimeout = value;
}

/// <inheritdoc/>
public override int WriteTimeout
{
get => BaseStream.WriteTimeout;
set => BaseStream.WriteTimeout = value;
get => stream.WriteTimeout;
set => stream.WriteTimeout = value;
}

/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
if (disposing && !leaveOpen)
BaseStream.Dispose();
stream.Dispose();
base.Dispose(disposing);
}

/// <inheritdoc/>
public override async ValueTask DisposeAsync()
{
if (!leaveOpen)
await BaseStream.DisposeAsync().ConfigureAwait(false);
await stream.DisposeAsync().ConfigureAwait(false);
await base.DisposeAsync().ConfigureAwait(false);
}
}
Loading

0 comments on commit 3e6ff7c

Please sign in to comment.