< Summary

Information
Class: MyNet.Utilities.StreamExtensions
Assembly: MyNet.Utilities
File(s): https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.Utilities/Extensions/StreamExtensions.cs
Tag: 323_28699572109
Line coverage
93%
Covered lines: 102
Uncovered lines: 7
Coverable lines: 109
Total lines: 319
Line coverage: 93.5%
Branch coverage
63%
Covered branches: 19
Total branches: 30
Branch coverage: 63.3%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
WriteBytes(...)100%22100%
WriteBytesAsync()50%2285.71%
ReadAllBytes(...)50%8662.5%
ReadAllBytesAsync()50%7672.72%
WriteString(...)50%22100%
WriteStringAsync()100%22100%
ReadAsString(...)50%22100%
ReadAsStringAsync()100%22100%
WriteXml(...)100%11100%
WriteXmlAsync()100%11100%
ReadXml(...)50%22100%
ReadXmlAsync()50%22100%
Rewind(...)100%22100%
.cctor()100%11100%

File(s)

https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.Utilities/Extensions/StreamExtensions.cs

#LineLine coverage
 1// -----------------------------------------------------------------------
 2// <copyright file="StreamExtensions.cs" company="Stéphane ANDRE">
 3// Copyright (c) Stéphane ANDRE. All rights reserved.
 4// </copyright>
 5// -----------------------------------------------------------------------
 6
 7using System;
 8using System.Diagnostics.CodeAnalysis;
 9using System.IO;
 10using System.Text;
 11using System.Threading;
 12using System.Threading.Tasks;
 13using System.Xml;
 14using System.Xml.Serialization;
 15
 16#pragma warning disable IDE0130 // Namespace does not match folder structure
 17namespace MyNet.Utilities;
 18#pragma warning restore IDE0130 // Namespace does not match folder structure
 19
 20[SuppressMessage("Reliability", "CA2007:Consider calling ConfigureAwait on the awaited task", Justification = "Library c
 21public static class StreamExtensions
 22{
 23    private const int DefaultBufferSize = 81920;
 24
 25    extension(Stream stream)
 26    {
 27        /// <summary>
 28        /// Writes the specified byte array to the stream.
 29        /// </summary>
 30        /// <param name="buffer">The buffer to write.</param>
 31        public void WriteBytes(byte[] buffer)
 32        {
 933            ArgumentNullException.ThrowIfNull(buffer);
 34
 635            if (buffer.Length == 0)
 336                return;
 37
 338            stream.Write(buffer);
 339        }
 40
 41        /// <summary>
 42        /// Writes the specified byte array to the stream asynchronously.
 43        /// </summary>
 44        /// <param name="buffer">The buffer to write.</param>
 45        /// <param name="cancellationToken">The cancellation token.</param>
 46        /// <returns>A task representing the asynchronous operation.</returns>
 47        public async ValueTask WriteBytesAsync(
 48            byte[] buffer,
 49            CancellationToken cancellationToken = default)
 50        {
 351            ArgumentNullException.ThrowIfNull(buffer);
 52
 353            if (buffer.Length == 0)
 054                return;
 55
 356            await stream
 357                .WriteAsync(buffer, cancellationToken)
 358                .ConfigureAwait(false);
 359        }
 60
 61        /// <summary>
 62        /// Reads the entire stream into a byte array.
 63        /// </summary>
 64        /// <returns>The stream content as a byte array.</returns>
 65        public byte[] ReadAllBytes()
 66        {
 667            if (stream is MemoryStream memoryStream &&
 668                memoryStream.TryGetBuffer(out var segment))
 69            {
 070                return segment.Array is not null
 071                    ? segment.Array.AsSpan(0, (int)memoryStream.Length).ToArray()
 072                    : memoryStream.ToArray();
 73            }
 74
 675            using var ms = new MemoryStream();
 76
 677            stream.CopyTo(ms, DefaultBufferSize);
 78
 679            return ms.ToArray();
 80        }
 81
 82        /// <summary>
 83        /// Reads the entire stream into a byte array asynchronously.
 84        /// </summary>
 85        /// <param name="cancellationToken">The cancellation token.</param>
 86        /// <returns>The stream content as a byte array.</returns>
 87        public async ValueTask<byte[]> ReadAllBytesAsync(
 88            CancellationToken cancellationToken = default)
 89        {
 690            if (stream is MemoryStream memoryStream &&
 691                memoryStream.TryGetBuffer(out var segment))
 92            {
 093                return segment.Array is not null
 094                    ? segment.Array.AsSpan(0, (int)memoryStream.Length).ToArray()
 095                    : memoryStream.ToArray();
 96            }
 97
 698            await using var ms = new MemoryStream();
 99
 6100            await stream
 6101                .CopyToAsync(ms, DefaultBufferSize, cancellationToken)
 6102                .ConfigureAwait(false);
 103
 6104            return ms.ToArray();
 6105        }
 106
 107        /// <summary>
 108        /// Writes the specified string to the stream using UTF8 encoding.
 109        /// </summary>
 110        /// <param name="value">The string to write.</param>
 111        /// <param name="encoding">The encoding to use.</param>
 112        /// <param name="leaveOpen">Whether to leave the stream open.</param>
 113        public void WriteString(
 114            string value,
 115            Encoding? encoding = null,
 116            bool leaveOpen = true)
 117        {
 6118            ArgumentNullException.ThrowIfNull(value);
 119
 3120            using var writer = new StreamWriter(
 3121                stream,
 3122                encoding ?? Encoding.UTF8,
 3123                DefaultBufferSize,
 3124                leaveOpen);
 125
 3126            writer.Write(value);
 3127            writer.Flush();
 3128        }
 129
 130        /// <summary>
 131        /// Writes the specified string to the stream asynchronously using UTF8 encoding.
 132        /// </summary>
 133        /// <param name="value">The string to write.</param>
 134        /// <param name="encoding">The encoding to use.</param>
 135        /// <param name="leaveOpen">Whether to leave the stream open.</param>
 136        /// <param name="cancellationToken">The cancellation token.</param>
 137        public async ValueTask WriteStringAsync(
 138            string value,
 139            Encoding? encoding = null,
 140            bool leaveOpen = true,
 141            CancellationToken cancellationToken = default)
 142        {
 3143            ArgumentNullException.ThrowIfNull(value);
 144
 3145            await using var writer = new StreamWriter(
 3146                stream,
 3147                encoding ?? Encoding.UTF8,
 3148                DefaultBufferSize,
 3149                leaveOpen);
 150
 3151            await writer
 3152                .WriteAsync(value.AsMemory(), cancellationToken)
 3153                .ConfigureAwait(false);
 154
 3155            await writer
 3156                .FlushAsync(cancellationToken)
 3157                .ConfigureAwait(false);
 3158        }
 159
 160        /// <summary>
 161        /// Reads the entire stream as a string.
 162        /// </summary>
 163        /// <param name="encoding">The encoding to use.</param>
 164        /// <param name="leaveOpen">Whether to leave the stream open.</param>
 165        /// <returns>The stream content as a string.</returns>
 166        public string ReadAsString(
 167            Encoding? encoding = null,
 168            bool leaveOpen = true)
 169        {
 3170            using var reader = new StreamReader(
 3171                stream,
 3172                encoding ?? Encoding.UTF8,
 3173                detectEncodingFromByteOrderMarks: true,
 3174                DefaultBufferSize,
 3175                leaveOpen);
 176
 3177            return reader.ReadToEnd();
 178        }
 179
 180        /// <summary>
 181        /// Reads the entire stream as a string asynchronously.
 182        /// </summary>
 183        /// <param name="encoding">The encoding to use.</param>
 184        /// <param name="leaveOpen">Whether to leave the stream open.</param>
 185        /// <param name="cancellationToken">The cancellation token.</param>
 186        /// <returns>The stream content as a string.</returns>
 187        public async ValueTask<string> ReadAsStringAsync(
 188            Encoding? encoding = null,
 189            bool leaveOpen = true,
 190            CancellationToken cancellationToken = default)
 191        {
 3192            using var reader = new StreamReader(
 3193                stream,
 3194                encoding ?? Encoding.UTF8,
 3195                detectEncodingFromByteOrderMarks: true,
 3196                DefaultBufferSize,
 3197                leaveOpen);
 198
 3199            return await reader
 3200                .ReadToEndAsync(cancellationToken)
 3201                .ConfigureAwait(false);
 3202        }
 203
 204        /// <summary>
 205        /// Serializes an object as XML into the stream.
 206        /// </summary>
 207        /// <typeparam name="T">The object type.</typeparam>
 208        /// <param name="value">The object to serialize.</param>
 209        /// <param name="leaveOpen">Whether to leave the stream open.</param>
 210        public void WriteXml<T>(
 211            T value,
 212            bool leaveOpen = true)
 213        {
 6214            ArgumentNullException.ThrowIfNull(value);
 215
 3216            var serializer = XmlSerializerCache<T>.Instance;
 217
 3218            var settings = new XmlWriterSettings { Async = false, Indent = true, Encoding = Encoding.UTF8, CloseOutput =
 219
 3220            using var writer = XmlWriter.Create(stream, settings);
 221
 3222            serializer.Serialize(writer, value);
 3223        }
 224
 225        /// <summary>
 226        /// Serializes an object as XML into the stream asynchronously.
 227        /// </summary>
 228        /// <typeparam name="T">The object type.</typeparam>
 229        /// <param name="value">The object to serialize.</param>
 230        /// <param name="leaveOpen">Whether to leave the stream open.</param>
 231        /// <param name="cancellationToken">The cancellation token.</param>
 232        public async ValueTask WriteXmlAsync<T>(
 233            T value,
 234            bool leaveOpen = true,
 235            CancellationToken cancellationToken = default)
 236        {
 3237            ArgumentNullException.ThrowIfNull(value);
 238
 3239            var serializer = XmlSerializerCache<T>.Instance;
 240
 3241            var settings = new XmlWriterSettings { Async = true, Indent = true, Encoding = Encoding.UTF8, CloseOutput = 
 242
 3243            await using var writer = XmlWriter.Create(stream, settings);
 244
 3245            serializer.Serialize(writer, value);
 246
 3247            await writer
 3248                .FlushAsync()
 3249                .ConfigureAwait(false);
 250
 3251            cancellationToken.ThrowIfCancellationRequested();
 3252        }
 253
 254        /// <summary>
 255        /// Deserializes an object from XML.
 256        /// </summary>
 257        /// <typeparam name="T">The object type.</typeparam>
 258        /// <param name="leaveOpen">Whether to leave the stream open.</param>
 259        /// <returns>The deserialized object.</returns>
 260        public T? ReadXml<T>(bool leaveOpen = true)
 261        {
 3262            var serializer = XmlSerializerCache<T>.Instance;
 263
 3264            var settings = new XmlReaderSettings { Async = false, CloseInput = !leaveOpen };
 265
 3266            using var reader = XmlReader.Create(stream, settings);
 267
 3268            return serializer.Deserialize(reader) is T result
 3269                ? result
 3270                : default;
 271        }
 272
 273        /// <summary>
 274        /// Deserializes an object from XML asynchronously.
 275        /// </summary>
 276        /// <typeparam name="T">The object type.</typeparam>
 277        /// <param name="leaveOpen">Whether to leave the stream open.</param>
 278        /// <param name="cancellationToken">The cancellation token.</param>
 279        /// <returns>The deserialized object.</returns>
 280        public async ValueTask<T?> ReadXmlAsync<T>(
 281            bool leaveOpen = true,
 282            CancellationToken cancellationToken = default)
 283        {
 3284            var serializer = XmlSerializerCache<T>.Instance;
 285
 3286            var settings = new XmlReaderSettings { Async = true, CloseInput = !leaveOpen };
 287
 3288            using var reader = XmlReader.Create(stream, settings);
 289
 3290            await reader
 3291                .MoveToContentAsync()
 3292                .ConfigureAwait(false);
 293
 3294            cancellationToken.ThrowIfCancellationRequested();
 295
 3296            return serializer.Deserialize(reader) is T result
 3297                ? result
 3298                : default;
 3299        }
 300
 301        /// <summary>
 302        /// Rewinds the stream to the beginning if seekable.
 303        /// </summary>
 304        public void Rewind()
 305        {
 6306            if (!stream.CanSeek)
 3307                return;
 308
 3309            stream.Position = 0;
 3310        }
 311    }
 312
 313    private static class XmlSerializerCache<T>
 314    {
 3315        public static readonly XmlSerializer Instance =
 3316            new(typeof(T));
 317    }
 318}
 319