namespace Just.Core.Extensions; /// /// Provides extension methods for to fully populate buffers. /// public static class SystemIOStreamExtensions { /// /// Reads data from the stream until the specified section of the buffer is filled. /// /// The stream to read from /// The buffer to populate /// The starting offset in the buffer /// The number of bytes to read /// Thrown when is null /// Thrown when or is invalid /// Thrown if the stream ends before filling the buffer /// Thrown for I/O errors during reading public static void Populate(this Stream stream, byte[] buffer, int offset, int length) => stream.Populate(buffer.AsSpan(offset, length)); /// /// Reads data from the stream until the entire buffer is filled. /// /// The stream to read from /// The buffer to populate /// Thrown when is null /// Thrown if the stream ends before filling the buffer /// Thrown for I/O errors during reading public static void Populate(this Stream stream, byte[] buffer) => stream.Populate(buffer.AsSpan()); /// /// Reads data from the stream until the specified span is filled. /// /// The stream to read from /// The span to populate /// Thrown when is null /// Thrown if the stream ends before filling the buffer /// Thrown for I/O errors during reading public static void Populate(this Stream stream, Span buffer) { ArgumentNullException.ThrowIfNull(stream); while (!buffer.IsEmpty) { var bytesRead = stream.Read(buffer); if (bytesRead == 0) { throw new EndOfStreamException(); } buffer = buffer[bytesRead..]; } } /// /// Asynchronously reads data from the stream until the entire buffer is filled. /// /// The stream to read from /// The buffer to populate /// Cancellation token /// A ValueTask representing the asynchronous operation /// Thrown when is null /// Thrown if the stream ends before filling the buffer /// Thrown if canceled via cancellation token /// Thrown for I/O errors during reading public static ValueTask PopulateAsync(this Stream stream, byte[] buffer, CancellationToken cancellationToken = default) => stream.PopulateAsync(buffer.AsMemory(), cancellationToken); /// /// Asynchronously reads data from the stream until the specified section of the buffer is filled. /// /// The stream to read from /// The buffer to populate /// The starting offset in the buffer /// The number of bytes to read /// Cancellation token /// A ValueTask representing the asynchronous operation /// Thrown when is null /// Thrown when or is invalid /// Thrown if the stream ends before filling the buffer /// Thrown if canceled via cancellation token /// Thrown for I/O errors during reading public static ValueTask PopulateAsync(this Stream stream, byte[] buffer, int offset, int length, CancellationToken cancellationToken = default) => stream.PopulateAsync(buffer.AsMemory(offset, length), cancellationToken); /// /// Asynchronously reads data from the stream until the specified memory region is filled. /// /// The stream to read from /// The memory region to populate /// Cancellation token /// A ValueTask representing the asynchronous operation /// Thrown when is null /// Thrown if the stream ends before filling the buffer /// Thrown if canceled via cancellation token /// Thrown for I/O errors during reading public static async ValueTask PopulateAsync(this Stream stream, Memory buffer, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(stream); while (!buffer.IsEmpty) { cancellationToken.ThrowIfCancellationRequested(); var bytesRead = await stream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false); if (bytesRead == 0) { throw new EndOfStreamException(); } buffer = buffer[bytesRead..]; } } }