< Summary

Class:Azure.Core.BinaryData
Assembly:Azure.Core.Experimental
File(s):C:\Git\azure-sdk-for-net\sdk\core\Azure.Core.Experimental\src\Primitives\BinaryData.cs
Covered lines:56
Uncovered lines:1
Coverable lines:57
Total lines:330
Line coverage:98.2% (56 of 57)
Covered branches:13
Total branches:14
Branch coverage:92.8% (13 of 14)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.cctor()-100%100%
get_Bytes()-100%100%
.ctor(...)-100%100%
.ctor(...)-100%100%
.ctor(...)-100%100%
FromMemory(...)-100%100%
FromStream(...)-100%100%
FromStreamAsync()-100%100%
FromStreamAsync()-100%100%
Serialize(...)-100%100%
SerializeAsync()-100%100%
Serialize(...)-100%100%
SerializeAsync()-100%100%
SerializeInternalAsync()-100%100%
ToString()-80%50%
ToStream()-100%100%
Deserialize(...)-100%100%
DeserializeAsync()-100%100%
Deserialize(...)-100%100%
DeserializeAsync()-100%100%
DeserializeInternalAsync()-100%100%
op_Implicit(...)-100%100%
Equals(...)-100%100%
GetHashCode()-100%100%

File(s)

C:\Git\azure-sdk-for-net\sdk\core\Azure.Core.Experimental\src\Primitives\BinaryData.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using System;
 5using System.ComponentModel;
 6using System.IO;
 7using System.Runtime.InteropServices;
 8using System.Text;
 9using System.Threading;
 10using System.Threading.Tasks;
 11using Azure.Core.Pipeline;
 12using Azure.Core.Serialization;
 13
 14namespace Azure.Core
 15{
 16    /// <summary>
 17    /// A lightweight abstraction for a payload of bytes. This type integrates with <see cref="ObjectSerializer"/>
 18    /// to allow for serializing and deserializing payloads.
 19    ///
 20    /// The ownership model of the underlying bytes varies depending on how the instance is constructed:
 21    ///
 22    /// If created using the static factory method, <see cref="FromMemory(ReadOnlyMemory{byte})"/>,
 23    /// the passed in bytes will be wrapped, rather than copied. This is useful in scenarios where performance
 24    /// is critical and/or ownership of the bytes is controlled completely by the consumer, thereby allowing the
 25    /// enforcement of whatever ownership model is needed.
 26    ///
 27    /// If created using the <see cref="BinaryData(ReadOnlySpan{byte})"/> constructor, <see cref="BinaryData"/> will
 28    /// maintain its own copy of the underlying bytes. This usage is geared more towards scenarios where the ownership
 29    /// of the bytes might be ambiguous to users of the consuming code. By making a copy of the bytes, the payload is
 30    /// guaranteed to be immutable.
 31    ///
 32    /// For all other constructors and static factory methods, BinaryData will assume ownership of the underlying bytes.
 33    /// </summary>
 34    public readonly struct BinaryData
 35    {
 36        private const int CopyToBufferSize = 81920;
 37
 238        private static readonly UTF8Encoding s_encoding = new UTF8Encoding(false);
 39
 40        /// <summary>
 41        /// The backing store for the <see cref="BinaryData"/> instance.
 42        /// </summary>
 15843        public ReadOnlyMemory<byte> Bytes { get; }
 44
 45        /// <summary>
 46        /// Creates a binary data instance by making a copy
 47        /// of the passed in bytes.
 48        /// </summary>
 49        /// <param name="data">Byte data.</param>
 50        public BinaryData(ReadOnlySpan<byte> data)
 51        {
 252            Bytes = data.ToArray();
 253        }
 54
 55        /// <summary>
 56        /// Creates a binary data instance by wrapping the
 57        /// passed in bytes.
 58        /// </summary>
 59        /// <param name="data">Byte data.</param>
 60        private BinaryData(ReadOnlyMemory<byte> data)
 61        {
 3862            Bytes = data;
 3863        }
 64        /// <summary>
 65        /// Creates a binary data instance from a string by converting
 66        /// the string to bytes using UTF-8 encoding.
 67        /// </summary>
 68        /// <param name="data">The string data.</param>
 69        /// <returns>A <see cref="BinaryData"/> instance.</returns>
 70        /// <remarks>The byte order mark is not included as part of the encoding process.</remarks>
 71        public BinaryData(string data)
 72        {
 273            Bytes = s_encoding.GetBytes(data);
 274        }
 75
 76        /// <summary>
 77        /// Creates a binary data instance by wrapping the passed in
 78        /// <see cref="ReadOnlyMemory{Byte}"/>.
 79        /// </summary>
 80        /// <param name="data"></param>
 81        /// <returns>A <see cref="BinaryData"/> instance.</returns>
 82        public static BinaryData FromMemory(ReadOnlyMemory<byte> data) =>
 1883            new BinaryData(data);
 84
 85        /// <summary>
 86        /// Creates a binary data instance from the specified stream.
 87        /// </summary>
 88        /// <param name="stream">Stream containing the data.</param>
 89        /// <returns>A <see cref="BinaryData"/> instance.</returns>
 90        public static BinaryData FromStream(Stream stream) =>
 891            FromStreamAsync(stream, false).EnsureCompleted();
 92
 93        /// <summary>
 94        /// Creates a binary data instance from the specified stream.
 95        /// </summary>
 96        /// <param name="stream">Stream containing the data.</param>
 97        /// <param name="cancellationToken">An optional<see cref="CancellationToken"/> instance to signal
 98        /// the request to cancel the operation.</param>
 99        /// <returns>A <see cref="BinaryData"/> instance.</returns>
 100        public static async Task<BinaryData> FromStreamAsync(
 101            Stream stream,
 102            CancellationToken cancellationToken = default) =>
 4103            await FromStreamAsync(stream, true, cancellationToken).ConfigureAwait(false);
 104
 105        private static async Task<BinaryData> FromStreamAsync(
 106            Stream stream,
 107            bool async,
 108            CancellationToken cancellationToken = default)
 109        {
 12110            Argument.AssertNotNull(stream, nameof(stream));
 8111            if (stream.CanSeek && stream.Length > int.MaxValue)
 112            {
 2113                throw new ArgumentOutOfRangeException(
 2114                    nameof(stream),
 2115                    "Stream length must be less than Int32.MaxValue");
 116            }
 6117            using (var memoryStream = new MemoryStream())
 118            {
 6119                if (async)
 120                {
 2121                    await stream.CopyToAsync(memoryStream, CopyToBufferSize, cancellationToken).ConfigureAwait(false);
 122                }
 123                else
 124                {
 4125                    stream.CopyTo(memoryStream);
 126                }
 6127                return new BinaryData((ReadOnlyMemory<byte>) memoryStream.ToArray());
 128            }
 6129        }
 130
 131        /// <summary>
 132        /// Creates a BinaryData instance from the specified data using
 133        /// the <see cref="JsonObjectSerializer"/>.
 134        /// </summary>
 135        /// <typeparam name="T">The type of the data.</typeparam>
 136        /// <param name="data">The data to use.</param>
 137        /// <param name="cancellationToken">The <see cref="CancellationToken"/> to use during serialization.</param>
 138        /// <returns>A <see cref="BinaryData"/> instance.</returns>
 139        public static BinaryData Serialize<T>(
 140            T data,
 141            CancellationToken cancellationToken = default) =>
 4142            Serialize<T>(data, new JsonObjectSerializer(), cancellationToken);
 143
 144        /// <summary>
 145        /// Creates a BinaryData instance from the specified data
 146        /// using the <see cref="JsonObjectSerializer"/>.
 147        /// </summary>
 148        /// <typeparam name="T">The type of the data.</typeparam>
 149        /// <param name="data">The data to use.</param>
 150        /// <param name="cancellationToken">The <see cref="CancellationToken"/> to use during serialization.</param>
 151        /// <returns>A <see cref="BinaryData"/> instance.</returns>
 152        public static async Task<BinaryData> SerializeAsync<T>(
 153            T data,
 154            CancellationToken cancellationToken = default) =>
 4155            await SerializeInternalAsync<T>(data, new JsonObjectSerializer(), true, cancellationToken).ConfigureAwait(fa
 156
 157        /// <summary>
 158        /// Creates a BinaryData instance from the specified data using
 159        /// the provided <see cref="ObjectSerializer"/>.
 160        /// </summary>
 161        /// <typeparam name="T">The type of the data.</typeparam>
 162        /// <param name="data">The data to use.</param>
 163        /// <param name="serializer">The serializer to serialize
 164        /// the data.</param>
 165        /// <param name="cancellationToken">The <see cref="CancellationToken"/> to use during serialization.</param>
 166        /// <returns>A <see cref="BinaryData"/> instance.</returns>
 167        public static BinaryData Serialize<T>(
 168            T data,
 169            ObjectSerializer serializer,
 170            CancellationToken cancellationToken = default) =>
 10171            SerializeInternalAsync<T>(data, serializer, false, cancellationToken).EnsureCompleted();
 172
 173        /// <summary>
 174        /// Creates a BinaryData instance from the specified data using
 175        /// the provided <see cref="ObjectSerializer"/>.
 176        /// </summary>
 177        /// <typeparam name="T">The type of the data.</typeparam>
 178        /// <param name="data">The data to use.</param>
 179        /// <param name="serializer">The serializer to serialize
 180        /// the data.</param>
 181        /// <param name="cancellationToken">The <see cref="CancellationToken"/> to use during serialization.</param>
 182        /// <returns>A <see cref="BinaryData"/> instance.</returns>
 183        public static async Task<BinaryData> SerializeAsync<T>(
 184            T data,
 185            ObjectSerializer serializer,
 186            CancellationToken cancellationToken = default) =>
 4187            await SerializeInternalAsync<T>(data, serializer, true, cancellationToken).ConfigureAwait(false);
 188
 189        private static async Task<BinaryData> SerializeInternalAsync<T>(
 190            T data,
 191            ObjectSerializer serializer,
 192            bool async,
 193            CancellationToken cancellationToken)
 194        {
 18195            Argument.AssertNotNull(serializer, nameof(serializer));
 14196            using var memoryStream = new MemoryStream();
 14197            if (async)
 198            {
 6199                await serializer.SerializeAsync(memoryStream, data, typeof(T), cancellationToken).ConfigureAwait(false);
 200            }
 201            else
 202            {
 8203                serializer.Serialize(memoryStream, data, typeof(T), cancellationToken);
 204            }
 14205            return new BinaryData((ReadOnlyMemory<byte>) memoryStream.ToArray());
 14206        }
 207
 208        /// <summary>
 209        /// Converts the BinaryData to a string using UTF-8.
 210        /// </summary>
 211        /// <returns>The string representation of the data.</returns>
 212        public override string ToString()
 213        {
 4214            if (MemoryMarshal.TryGetArray(
 4215                Bytes,
 4216                out ArraySegment<byte> data))
 217            {
 4218                return s_encoding.GetString(data.Array, data.Offset, data.Count);
 219            }
 0220            return s_encoding.GetString(Bytes.ToArray());
 221        }
 222
 223        /// <summary>
 224        /// Converts the BinaryData to a stream.
 225        /// </summary>
 226        /// <returns>A stream representing the data.</returns>
 227        public Stream ToStream() =>
 112228            new ReadOnlyMemoryStream(Bytes);
 229
 230        /// <summary>
 231        /// Converts the BinaryData to the specified type using
 232        /// the provided <see cref="ObjectSerializer"/>.
 233        /// </summary>
 234        /// <typeparam name="T">The type that the data should be
 235        /// converted to.</typeparam>
 236        /// <param name="serializer">The serializer to use
 237        /// when deserializing the data.</param>
 238        /// <param name="cancellationToken">The <see cref="CancellationToken"/> to use during deserialization.</param>
 239        ///<returns>The data converted to the specified type.</returns>
 240        public T Deserialize<T>(ObjectSerializer serializer, CancellationToken cancellationToken = default) =>
 26241            DeserializeInternalAsync<T>(serializer, false, cancellationToken).EnsureCompleted();
 242
 243        /// <summary>
 244        /// Converts the BinaryData to the specified type using the
 245        /// <see cref="JsonObjectSerializer"/>.
 246        /// </summary>
 247        /// <typeparam name="T">The type that the data should be
 248        /// converted to.</typeparam>
 249        /// <param name="cancellationToken">The <see cref="CancellationToken"/> to use during deserialization.</param>
 250        ///<returns>The data cast to the specified type. If the cast cannot
 251        ///be performed, an <see cref="InvalidCastException"/> will be
 252        ///thrown.</returns>
 253        public async ValueTask<T> DeserializeAsync<T>(CancellationToken cancellationToken = default) =>
 28254            await DeserializeInternalAsync<T>(new JsonObjectSerializer(), true, cancellationToken).ConfigureAwait(false)
 255
 256        /// <summary>
 257        /// Converts the BinaryData to the specified type using the
 258        /// <see cref="JsonObjectSerializer"/>.
 259        /// </summary>
 260        /// <typeparam name="T">The type that the data should be
 261        /// converted to.</typeparam>
 262        /// <param name="cancellationToken">The <see cref="CancellationToken"/> to use during deserialization.</param>
 263        ///<returns>The data converted to the specified type.</returns>
 264        public T Deserialize<T>(CancellationToken cancellationToken = default) =>
 28265            DeserializeInternalAsync<T>(new JsonObjectSerializer(), false, cancellationToken).EnsureCompleted();
 266
 267        /// <summary>
 268        /// Converts the BinaryData to the specified type using the
 269        /// provided <see cref="ObjectSerializer"/>.
 270        /// </summary>
 271        /// <typeparam name="T">The type that the data should be
 272        /// converted to.</typeparam>
 273        /// <param name="serializer">The serializer to use
 274        /// when deserializing the data.</param>
 275        /// <param name="cancellationToken">The <see cref="CancellationToken"/> to use during deserialization.</param>
 276        ///<returns>The data cast to the specified type. If the cast cannot
 277        ///be performed, an <see cref="InvalidCastException"/> will be
 278        ///thrown.</returns>
 279        public async ValueTask<T> DeserializeAsync<T>(ObjectSerializer serializer, CancellationToken cancellationToken =
 26280            await DeserializeInternalAsync<T>(serializer, true, cancellationToken).ConfigureAwait(false);
 281
 282        private async ValueTask<T> DeserializeInternalAsync<T>(
 283            ObjectSerializer serializer,
 284            bool async,
 285            CancellationToken cancellationToken)
 286        {
 108287            Argument.AssertNotNull(serializer, nameof(serializer));
 104288            if (async)
 289            {
 52290                return (T)await serializer.DeserializeAsync(
 52291                    ToStream(),
 52292                    typeof(T),
 52293                    cancellationToken)
 52294                    .ConfigureAwait(false);
 295            }
 296            else
 297            {
 52298                return (T)serializer.Deserialize(ToStream(), typeof(T), cancellationToken);
 299            }
 96300        }
 301
 302        /// <summary>
 303        /// Implicit conversion to bytes.
 304        /// </summary>
 305        /// <param name="data"></param>
 306        public static implicit operator ReadOnlyMemory<byte>(
 307            BinaryData data) =>
 4308            data.Bytes;
 309
 310        /// <summary>
 311        /// Two BinaryData objects are equal if the memory regions point to the same array and have the same length.
 312        /// The method does not check to see if the contents are equal.
 313        /// </summary>
 314        /// <param name="obj">The BinaryData to compare.</param>
 315        /// <returns>true if the current instance and other are equal; otherwise, false.</returns>
 316        [EditorBrowsable(EditorBrowsableState.Never)]
 317        public override bool Equals(object? obj)
 318        {
 10319            if (obj is BinaryData data)
 320            {
 8321                return data.Bytes.Equals(Bytes);
 322            }
 2323            return false;
 324        }
 325        /// <inheritdoc />
 326        [EditorBrowsable(EditorBrowsableState.Never)]
 327        public override int GetHashCode() =>
 10328            Bytes.GetHashCode();
 329    }
 330}